@africode/core 5.0.4 โ 5.0.6
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/AGENTS.md +583 -0
- package/AGENT_INSTRUCTIONS.md +595 -0
- package/COMPONENT_SCHEMA.json +990 -836
- package/README.md +32 -0
- package/components/index.js +14 -0
- package/components/ui-badge.js +61 -0
- package/components/ui-button.js +149 -0
- package/components/ui-card.js +75 -0
- package/components/ui-input.js +110 -0
- package/components/ui-switch.js +85 -0
- package/core/cli/commands/build.js +31 -1
- package/core/cli/commands/dev.js +38 -1
- package/core/lipa-namba-journey.js +28 -6
- package/dist/africode.js +672 -422
- package/dist/africode.js.map +9 -4
- package/dist/build-info.json +3 -3
- package/dist/components.js +554 -304
- package/dist/components.js.map +9 -4
- package/package.json +3 -1
- package/templates/starter-tailwind/src/pages/index.js +30 -0
- package/templates/starter-tailwind/tailwind.config.cjs +18 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
# ๐ค AGENTS.md โ AfriCode v5.0.0 Robot-First Specification
|
|
2
|
+
|
|
3
|
+
**Purpose**: This document defines the canonical technology stack, coding conventions, and framework grammar for all AI agents building on AfriCode. It ensures generated code is "native" and secure.
|
|
4
|
+
|
|
5
|
+
**Last Updated**: May 2, 2026
|
|
6
|
+
**Framework Version**: 5.0.0
|
|
7
|
+
**Target Deployment**: Bun Runtime (v1.3.12+) on AMD AI Cloud & Alibaba Cloud Assets
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ๐๏ธ Canonical Technology Stack
|
|
12
|
+
|
|
13
|
+
### Runtime & Build
|
|
14
|
+
- **Runtime**: Bun v1.3.12+ (native, all-in-one: runtime + bundler + test runner)
|
|
15
|
+
- **Language**: ES2024 JavaScript (native, no transpilation needed for modern syntax)
|
|
16
|
+
- **Module Format**: ESM (native Bun import/export)
|
|
17
|
+
- **Build System**: Bun.build() with custom plugins for SVG optimization
|
|
18
|
+
- **Development Server**: Bun.serve() with FileSystemRouter for automatic routing
|
|
19
|
+
|
|
20
|
+
### UI & Components
|
|
21
|
+
- **Component Model**: Web Components (Custom Elements + Shadow DOM + Slots)
|
|
22
|
+
- **State Management**: Proxy-based reactivity (core/state.js) โ zero virtual DOM
|
|
23
|
+
- **Styling**: CSS Variables + Logical Properties (CSS Containment Level 3)
|
|
24
|
+
- **Pattern Generation**: Procedural SVG (no asset uploads needed)
|
|
25
|
+
- **Message Protocol**: A2UI v1.0 (core/a2ui.js) for AI-generated interfaces
|
|
26
|
+
|
|
27
|
+
### Data & Persistence
|
|
28
|
+
- **Primary Store**: Bun.SQLite (synchronous API, ultra-fast)
|
|
29
|
+
- **Migration System**: Bun-native SQL scripts in migrations/ folder
|
|
30
|
+
- **Query Pattern**: Direct SQL with type-safe parameter binding
|
|
31
|
+
- **Cache Layer**: In-memory Proxy objects with automatic expiry
|
|
32
|
+
|
|
33
|
+
### Security & Compliance
|
|
34
|
+
- **Authentication**: Session-based (HttpOnly cookies + SameSite=Strict)
|
|
35
|
+
- **Hashing**: Argon2id (built into Bun)
|
|
36
|
+
- **Fintech Compliance**: NIDA CIG + TIPS + AML/FIU middleware
|
|
37
|
+
- **Cryptography**: Ed25519 for message signing (Bun.crypto)
|
|
38
|
+
- **CORS**: Frame-based origin isolation via Web Components
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## ๐ Canonical Directory Structure
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
AfriCode/
|
|
46
|
+
โโโ bin/ # CLI entry points
|
|
47
|
+
โ โโโ africode.js # Main CLI
|
|
48
|
+
โ โโโ create-africode.js # Project scaffolder
|
|
49
|
+
โโโ core/ # Framework internals (do not modify)
|
|
50
|
+
โ โโโ sdk.js # Main export
|
|
51
|
+
โ โโโ state.js # Reactive state engine
|
|
52
|
+
โ โโโ store.js # Global store singleton
|
|
53
|
+
โ โโโ a2ui.js # AI message protocol
|
|
54
|
+
โ โโโ compliance.js # Fintech middleware
|
|
55
|
+
โ โโโ bun-runtime.js # Bun server initialization
|
|
56
|
+
โ โโโ router.js # FileSystemRouter
|
|
57
|
+
โ โโโ html.js # HTML template utilities
|
|
58
|
+
โ โโโ patterns.js # SVG procedural generation
|
|
59
|
+
โ โโโ validation.js # Input validation schemas
|
|
60
|
+
โ โโโ server/ # Server utilities
|
|
61
|
+
โ โ โโโ auth.js # Session management
|
|
62
|
+
โ โ โโโ db.js # Database layer
|
|
63
|
+
โ โ โโโ render.js # SSR template rendering
|
|
64
|
+
โ โ โโโ router.js # Route handler utilities
|
|
65
|
+
โ โโโ cli/ # CLI implementation
|
|
66
|
+
โ โโโ commands/ # Command handlers
|
|
67
|
+
โโโ components/ # Web Components (pre-approved)
|
|
68
|
+
โ โโโ index.js # Component registry & exports
|
|
69
|
+
โ โโโ base.js # BaseElement class
|
|
70
|
+
โ โโโ button.js # Button component
|
|
71
|
+
โ โโโ card.js # Card component
|
|
72
|
+
โ โโโ cultural-card.js # Cultural card variant
|
|
73
|
+
โ โโโ kanga-card.js # Kanga pattern card
|
|
74
|
+
โ โโโ form.js # Form wrapper
|
|
75
|
+
โ โโโ input.js # Input control
|
|
76
|
+
โ โโโ select.js # Select dropdown
|
|
77
|
+
โ โโโ modal.js # Modal dialog
|
|
78
|
+
โ โโโ navbar.js # Navigation bar
|
|
79
|
+
โ โโโ [33 total components]
|
|
80
|
+
โโโ patterns/ # Procedural SVG generators
|
|
81
|
+
โ โโโ kente.js # Kente weaving patterns
|
|
82
|
+
โ โโโ shuka.js # Maasai Shuka tartan
|
|
83
|
+
โ โโโ ndebele.js # Ndebele geometric
|
|
84
|
+
โ โโโ kitenge.js # Kitenge florals
|
|
85
|
+
โ โโโ [8 regional patterns]
|
|
86
|
+
โโโ samples/ # ๐ Hand-curated LLM examples
|
|
87
|
+
โ โโโ README.md # Usage guide for agents
|
|
88
|
+
โ โโโ basic-app/ # Minimal app (5 files)
|
|
89
|
+
โ โ โโโ package.json
|
|
90
|
+
โ โ โโโ pages/index.html
|
|
91
|
+
โ โ โโโ styles/theme.css
|
|
92
|
+
โ โ โโโ core/app.js
|
|
93
|
+
โ โโโ fintech-kiosk/ # Payment flow (Lipa Namba)
|
|
94
|
+
โ โ โโโ pages/
|
|
95
|
+
โ โ โ โโโ index.html # Entry
|
|
96
|
+
โ โ โ โโโ [payment-id].html # Dynamic route
|
|
97
|
+
โ โ โ โโโ api/payment.js
|
|
98
|
+
โ โ โโโ components/
|
|
99
|
+
โ โ โ โโโ payment-form.js
|
|
100
|
+
โ โ โ โโโ nida-verify.js
|
|
101
|
+
โ โ โ โโโ confirmation.js
|
|
102
|
+
โ โ โโโ core/
|
|
103
|
+
โ โ โโโ merchant-service.js
|
|
104
|
+
โ โ โโโ compliance-check.js
|
|
105
|
+
โ โโโ cultural-showcase/ # Pattern display
|
|
106
|
+
โ โ โโโ pages/
|
|
107
|
+
โ โ โโโ components/
|
|
108
|
+
โ โ โโโ core/pattern-service.js
|
|
109
|
+
โ โโโ admin-dashboard/ # Multi-user app
|
|
110
|
+
โ โ โโโ pages/auth/login.html
|
|
111
|
+
โ โ โโโ pages/dashboard/
|
|
112
|
+
โ โ โโโ components/data-table.js
|
|
113
|
+
โ โ โโโ middleware/auth-check.js
|
|
114
|
+
โ โโโ [8+ regional examples]
|
|
115
|
+
โโโ migrations/ # SQL schema versioning
|
|
116
|
+
โ โโโ 001_initial_schema.sql # Base schema with compliance fields
|
|
117
|
+
โโโ styles/ # Design tokens
|
|
118
|
+
โ โโโ africanity.css # Main theme
|
|
119
|
+
โ โโโ typography.css # Type scale
|
|
120
|
+
โโโ tests/ # Test pyramid (70/20/10)
|
|
121
|
+
โ โโโ unit/ # 70% unit tests
|
|
122
|
+
โ โ โโโ state.test.js
|
|
123
|
+
โ โ โโโ patterns.test.js
|
|
124
|
+
โ โ โโโ validation.test.js
|
|
125
|
+
โ โ โโโ [compliance tests]
|
|
126
|
+
โ โโโ integration/ # 20% integration tests
|
|
127
|
+
โ โ โโโ a2ui.test.js
|
|
128
|
+
โ โ โโโ router.test.js
|
|
129
|
+
โ โ โโโ nida-flow.test.js # NIDA verification
|
|
130
|
+
โ โ โโโ tips-payment.test.js # TIPS payment
|
|
131
|
+
โ โ โโโ aml-screening.test.js
|
|
132
|
+
โ โโโ e2e/ # 10% critical journeys
|
|
133
|
+
โ โโโ signup-nida.test.js # Register + verify
|
|
134
|
+
โ โโโ lipa-namba.test.js # Payment flow
|
|
135
|
+
โ โโโ merchant-checkout.test.js
|
|
136
|
+
โโโ package.json # Main entry point metadata
|
|
137
|
+
โโโ bunfig.toml # Bun configuration
|
|
138
|
+
โโโ tsconfig.json # TypeScript settings (optional)
|
|
139
|
+
โโโ AGENTS.md # ๐ This file โ AI training spec
|
|
140
|
+
โโโ COMPONENT_SCHEMA.json # ๐ Auto-generated component manifest
|
|
141
|
+
โโโ README.md # User documentation
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## ๐ฏ Coding Conventions (AI Must Follow)
|
|
147
|
+
|
|
148
|
+
### File Naming & Structure
|
|
149
|
+
- **Component files**: `kebab-case.js` (e.g., `payment-form.js`)
|
|
150
|
+
- **Utility/service files**: `kebab-case.js` (e.g., `merchant-service.js`)
|
|
151
|
+
- **Test files**: `*.test.js` (e.g., `nida-flow.test.js`)
|
|
152
|
+
- **One component per file** (no monoliths)
|
|
153
|
+
- **Named exports for utilities**, default export for components
|
|
154
|
+
|
|
155
|
+
### JavaScript Patterns
|
|
156
|
+
|
|
157
|
+
#### โ
CORRECT
|
|
158
|
+
```javascript
|
|
159
|
+
// components/payment-form.js
|
|
160
|
+
export class PaymentForm extends HTMLElement {
|
|
161
|
+
constructor() {
|
|
162
|
+
super();
|
|
163
|
+
this.attachShadow({ mode: 'open' });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
connectedCallback() {
|
|
167
|
+
this.render();
|
|
168
|
+
this.setupEventListeners();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
render() {
|
|
172
|
+
this.shadowRoot.innerHTML = `...`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
setupEventListeners() {
|
|
176
|
+
this.addEventListener('submit', (e) => this.handleSubmit(e));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async handleSubmit(e) {
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
const result = await this.validate();
|
|
182
|
+
if (result.ok) this.dispatchEvent(new CustomEvent('success', { detail: result }));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
customElements.define('af-payment-form', PaymentForm);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### โ AVOID
|
|
190
|
+
```javascript
|
|
191
|
+
// DON'T use React JSX
|
|
192
|
+
const PaymentForm = () => <form>...</form>;
|
|
193
|
+
|
|
194
|
+
// DON'T use Vue/Svelte syntax
|
|
195
|
+
<script setup>
|
|
196
|
+
const form = ref(null);
|
|
197
|
+
</script>
|
|
198
|
+
|
|
199
|
+
// DON'T use external state libraries (Redux, Zustand)
|
|
200
|
+
import { store } from '@stores/payment';
|
|
201
|
+
|
|
202
|
+
// DON'T use DOM selectors without scoping
|
|
203
|
+
document.querySelector('.form'); // โ Global scope
|
|
204
|
+
|
|
205
|
+
// DO scope to Shadow DOM
|
|
206
|
+
this.shadowRoot.querySelector('.form'); // โ
Encapsulated
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### State Management Pattern
|
|
210
|
+
```javascript
|
|
211
|
+
// core/app-state.js (CORRECT)
|
|
212
|
+
import { createReactiveState } from 'africode/core/state.js';
|
|
213
|
+
|
|
214
|
+
export const appState = createReactiveState({
|
|
215
|
+
user: null,
|
|
216
|
+
payment: { amount: 0, status: 'idle' },
|
|
217
|
+
nida: { verified: false, nin: null }
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Subscribe to changes
|
|
221
|
+
appState.subscribe('payment.status', (newStatus) => {
|
|
222
|
+
console.log('Payment status changed:', newStatus);
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### API Route Pattern
|
|
227
|
+
```javascript
|
|
228
|
+
// pages/api/payment.js (CORRECT)
|
|
229
|
+
export async function POST(request) {
|
|
230
|
+
const body = await request.json();
|
|
231
|
+
|
|
232
|
+
// Validate input
|
|
233
|
+
const validation = validatePayload(body, paymentSchema);
|
|
234
|
+
if (!validation.ok) return new Response(validation.error, { status: 400 });
|
|
235
|
+
|
|
236
|
+
// Check compliance
|
|
237
|
+
const amlResult = await checkAMLScreening(body.amount);
|
|
238
|
+
if (!amlResult.ok) return new Response('Transaction blocked', { status: 403 });
|
|
239
|
+
|
|
240
|
+
// Process payment
|
|
241
|
+
const tx = await processPayment(body);
|
|
242
|
+
return new Response(JSON.stringify(tx), { status: 200 });
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Component Composition
|
|
247
|
+
```javascript
|
|
248
|
+
// pages/checkout.html (CORRECT)
|
|
249
|
+
<af-payment-form id="form">
|
|
250
|
+
<af-nida-verify slot="identity"></af-nida-verify>
|
|
251
|
+
<af-card slot="summary">
|
|
252
|
+
<h2>Order Summary</h2>
|
|
253
|
+
<af-price amount="50000"></af-price>
|
|
254
|
+
</af-card>
|
|
255
|
+
</af-payment-form>
|
|
256
|
+
|
|
257
|
+
<script type="module">
|
|
258
|
+
import 'africode/components/index.js';
|
|
259
|
+
|
|
260
|
+
const form = document.querySelector('af-payment-form');
|
|
261
|
+
form.addEventListener('success', (e) => {
|
|
262
|
+
console.log('Payment confirmed:', e.detail);
|
|
263
|
+
});
|
|
264
|
+
</script>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Error Handling
|
|
268
|
+
```javascript
|
|
269
|
+
// Middleware pattern
|
|
270
|
+
export function complianceCheck(handler) {
|
|
271
|
+
return async (request) => {
|
|
272
|
+
try {
|
|
273
|
+
const compliant = await validateCompliance(request);
|
|
274
|
+
if (!compliant) throw new Error('Compliance failed');
|
|
275
|
+
return await handler(request);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error('Compliance error:', error);
|
|
278
|
+
return new Response(
|
|
279
|
+
JSON.stringify({ error: error.message, code: 'COMPLIANCE_ERROR' }),
|
|
280
|
+
{ status: 403 }
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## ๐ Fintech Compliance Grammar
|
|
290
|
+
|
|
291
|
+
### NIDA Verification Flow
|
|
292
|
+
```javascript
|
|
293
|
+
// core/server/nida-flow.js
|
|
294
|
+
export async function verifyNIDA(nin, pin) {
|
|
295
|
+
// Step 1: Sign request with Ed25519 private key
|
|
296
|
+
const signature = await signRequest({ nin, timestamp: Date.now() }, privateKey);
|
|
297
|
+
|
|
298
|
+
// Step 2: Call CIG endpoint over TLS 1.3
|
|
299
|
+
const response = await fetch('https://api.nida.go.tz/cig/verify', {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
headers: {
|
|
302
|
+
'Content-Type': 'application/json',
|
|
303
|
+
'X-Signature': signature,
|
|
304
|
+
'X-Client-Id': 'africode-v5'
|
|
305
|
+
},
|
|
306
|
+
body: JSON.stringify({ nin, pin })
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// Step 3: Validate response signature
|
|
310
|
+
const data = await response.json();
|
|
311
|
+
const isValid = await verifySignature(data, data.signature, nidaPublicKey);
|
|
312
|
+
|
|
313
|
+
if (!isValid) throw new Error('Invalid signature from NIDA');
|
|
314
|
+
return data;
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### TIPS Payment Flow
|
|
319
|
+
```javascript
|
|
320
|
+
// core/server/tips-flow.js
|
|
321
|
+
export async function initiateP2PPayment(sender, receiver, amount) {
|
|
322
|
+
// Validate both parties exist in NIDA
|
|
323
|
+
await verifyNIDA(sender.nin);
|
|
324
|
+
await verifyNIDA(receiver.nin);
|
|
325
|
+
|
|
326
|
+
// Create TIPS transaction
|
|
327
|
+
const tipsPayload = {
|
|
328
|
+
transactionType: 'P2P',
|
|
329
|
+
senderNIN: sender.nin,
|
|
330
|
+
receiverNIN: receiver.nin,
|
|
331
|
+
amount: amount,
|
|
332
|
+
currency: 'TZS',
|
|
333
|
+
reference: generateReference(),
|
|
334
|
+
timestamp: new Date().toISOString()
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// Sign and send to TIPS
|
|
338
|
+
const tipsResponse = await callTIPS('/p2p/initiate', tipsPayload);
|
|
339
|
+
|
|
340
|
+
// Log for AML/FIU reporting
|
|
341
|
+
await logAMLTransaction(tipsResponse.transactionId, tipsPayload);
|
|
342
|
+
|
|
343
|
+
return tipsResponse;
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### AML Screening
|
|
348
|
+
```javascript
|
|
349
|
+
// core/server/aml-check.js
|
|
350
|
+
export async function screenTransaction(amount, nin) {
|
|
351
|
+
// Query FIU's AML database
|
|
352
|
+
const suspicious = await queryFIUList(nin);
|
|
353
|
+
if (suspicious) return { ok: false, reason: 'SUSPICIOUS_PARTY' };
|
|
354
|
+
|
|
355
|
+
// Check transaction limits
|
|
356
|
+
const dailyTotal = await getDailyTransactionTotal(nin);
|
|
357
|
+
if (dailyTotal + amount > 50_000_000) { // 50M TZS daily limit
|
|
358
|
+
return { ok: false, reason: 'AMOUNT_EXCEEDS_LIMIT' };
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Queue for AML reporting (24-hour window)
|
|
362
|
+
await queueAMLReport({
|
|
363
|
+
transactionId: generateId(),
|
|
364
|
+
amount,
|
|
365
|
+
nin,
|
|
366
|
+
timestamp: new Date()
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
return { ok: true };
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## ๐ฆ Component Manifest (COMPONENT_SCHEMA.json)
|
|
376
|
+
|
|
377
|
+
**Purpose**: Auto-generated JSON schema that whitelists safe components for AI generation. Prevents hallucinated HTML and enforces A2UI compliance.
|
|
378
|
+
|
|
379
|
+
**Generated by**: `scripts/generate-component-schema.js`
|
|
380
|
+
|
|
381
|
+
```json
|
|
382
|
+
{
|
|
383
|
+
"version": "5.0.0",
|
|
384
|
+
"timestamp": "2026-05-02T00:00:00Z",
|
|
385
|
+
"components": [
|
|
386
|
+
{
|
|
387
|
+
"tagName": "af-button",
|
|
388
|
+
"filePath": "components/button.js",
|
|
389
|
+
"slots": ["default"],
|
|
390
|
+
"attributes": {
|
|
391
|
+
"variant": { "type": "string", "enum": ["primary", "secondary", "ghost"], "default": "primary" },
|
|
392
|
+
"size": { "type": "string", "enum": ["sm", "md", "lg"], "default": "md" },
|
|
393
|
+
"disabled": { "type": "boolean", "default": false }
|
|
394
|
+
},
|
|
395
|
+
"events": [
|
|
396
|
+
{ "name": "click", "detail": { "type": "object" } }
|
|
397
|
+
],
|
|
398
|
+
"cssCustomProperties": [
|
|
399
|
+
"--af-button-bg",
|
|
400
|
+
"--af-button-text",
|
|
401
|
+
"--af-button-border"
|
|
402
|
+
],
|
|
403
|
+
"example": "<af-button variant=\"primary\" size=\"lg\">Click Me</af-button>",
|
|
404
|
+
"securityNotes": "Sanitizes slot content"
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"tagName": "af-nida-verify",
|
|
408
|
+
"filePath": "components/nida-verify.js",
|
|
409
|
+
"slots": [],
|
|
410
|
+
"attributes": {
|
|
411
|
+
"nin": { "type": "string", "required": true, "pattern": "^[0-9]{20}$" },
|
|
412
|
+
"pin": { "type": "string", "required": true }
|
|
413
|
+
},
|
|
414
|
+
"events": [
|
|
415
|
+
{ "name": "verified", "detail": { "verified": true, "user": {} } }
|
|
416
|
+
],
|
|
417
|
+
"complianceNotes": "NIDA CIG v2.1 compliant, Ed25519 signed requests"
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
"tagName": "af-payment-form",
|
|
421
|
+
"filePath": "components/payment-form.js",
|
|
422
|
+
"slots": ["identity", "summary"],
|
|
423
|
+
"attributes": {
|
|
424
|
+
"merchant-id": { "type": "string", "required": true },
|
|
425
|
+
"amount": { "type": "number", "required": true }
|
|
426
|
+
},
|
|
427
|
+
"events": [
|
|
428
|
+
{ "name": "success", "detail": { "transactionId": "", "status": "" } },
|
|
429
|
+
{ "name": "error", "detail": { "error": "", "code": "" } }
|
|
430
|
+
],
|
|
431
|
+
"complianceNotes": "Auto-screens AML, enforces TIPS standards"
|
|
432
|
+
}
|
|
433
|
+
],
|
|
434
|
+
"forbiddenPatterns": [
|
|
435
|
+
"eval()",
|
|
436
|
+
"innerHTML = userInput",
|
|
437
|
+
"fetch without CORS headers",
|
|
438
|
+
"localStorage for sensitive data"
|
|
439
|
+
]
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## โก Bun-Native Optimization Rules
|
|
446
|
+
|
|
447
|
+
### ๐ฏ Inversion of Control
|
|
448
|
+
```javascript
|
|
449
|
+
// โ OLD: Library pattern (user calls your code)
|
|
450
|
+
import { PaymentForm } from 'africode/components';
|
|
451
|
+
const form = new PaymentForm();
|
|
452
|
+
|
|
453
|
+
// โ
NEW: Framework pattern (framework owns lifecycle)
|
|
454
|
+
// Just add file: pages/checkout.html
|
|
455
|
+
// Bun.serve + FileSystemRouter auto-discovers and serves it
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### ๐ฏ Asset Optimization (Bun Plugins)
|
|
459
|
+
```javascript
|
|
460
|
+
// bunfig.toml - Bun configuration
|
|
461
|
+
[build]
|
|
462
|
+
plugins = ["./build-plugins/svg-optimizer.js"]
|
|
463
|
+
|
|
464
|
+
// build-plugins/svg-optimizer.js
|
|
465
|
+
export default {
|
|
466
|
+
name: 'svg-optimizer',
|
|
467
|
+
setup(build) {
|
|
468
|
+
build.onLoad({ filter: /\.svg$/ }, async (args) => {
|
|
469
|
+
const svg = await Bun.file(args.path).text();
|
|
470
|
+
const minified = minifySVG(svg);
|
|
471
|
+
return {
|
|
472
|
+
contents: `export default "${minified}"`,
|
|
473
|
+
loader: 'js'
|
|
474
|
+
};
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### ๐ฏ 5ms Startup Target
|
|
481
|
+
- No lazy imports in critical paths
|
|
482
|
+
- Bun.SQLite ready before route handling
|
|
483
|
+
- All validators pre-compiled at startup
|
|
484
|
+
- Compliance certificates pre-loaded in memory
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## ๐งช Test Pyramid (70/20/10)
|
|
489
|
+
|
|
490
|
+
### Unit Tests (70%) โ core/*/
|
|
491
|
+
```bash
|
|
492
|
+
bun test tests/unit/*.test.js
|
|
493
|
+
# Focus: individual functions, validators, pattern generators
|
|
494
|
+
# Example: patterns.test.js โ verify Kente weave algorithm
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Integration Tests (20%) โ pages/api/*/
|
|
498
|
+
```bash
|
|
499
|
+
bun test tests/integration/*.test.js
|
|
500
|
+
# Focus: A2UI rendering, router matching, compliance middleware
|
|
501
|
+
# Example: nida-flow.test.js โ full verification ceremony
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### E2E Tests (10%) โ critical user journeys
|
|
505
|
+
```bash
|
|
506
|
+
bun test tests/e2e/*.test.js
|
|
507
|
+
# Focus: signup-nida, lipa-namba payment, merchant-checkout
|
|
508
|
+
# Example: lipa-namba.test.js โ real TIPS transaction simulation
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## ๐ฅ Hot-Reload Middleware
|
|
514
|
+
|
|
515
|
+
```javascript
|
|
516
|
+
// core/hmr.js (CORRECT)
|
|
517
|
+
export function createHMRServer() {
|
|
518
|
+
return new WebSocket('ws://localhost:3001/hmr');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// In Bun.serve, call with --hot flag:
|
|
522
|
+
// bun run bin/africode.js dev --hot
|
|
523
|
+
// This enables:
|
|
524
|
+
// - File watching via Bun.watch()
|
|
525
|
+
// - Soft reloads (no session loss)
|
|
526
|
+
// - Database connection persistence
|
|
527
|
+
// - In-memory state retained
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## ๐ AI Agent Constraints
|
|
533
|
+
|
|
534
|
+
When building apps with this spec, AI agents MUST:
|
|
535
|
+
|
|
536
|
+
1. **Only use pre-approved components** from COMPONENT_SCHEMA.json
|
|
537
|
+
2. **Never generate raw HTML** โ use af-* Web Components
|
|
538
|
+
3. **Prefer AfriCode-native patterns first**; use external libraries only when they provide a clear, justified enhancement and are already supported by the project
|
|
539
|
+
4. **Always validate inputs** with schemas in core/validation.js
|
|
540
|
+
5. **Always call compliance middleware** before processing payments
|
|
541
|
+
6. **Always sign NIDA requests** with Ed25519 keys
|
|
542
|
+
7. **Always log transactions** for AML/FIU reporting
|
|
543
|
+
8. **Always use Bun-native APIs** (no Node.js polyfills)
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## ๐ Quick Verification
|
|
548
|
+
|
|
549
|
+
To verify an AI-generated app is "native" to AfriCode:
|
|
550
|
+
|
|
551
|
+
```bash
|
|
552
|
+
# Check component usage
|
|
553
|
+
grep -r "<af-" pages/ components/ | wc -l # Should be > 0
|
|
554
|
+
|
|
555
|
+
# Check for forbidden patterns
|
|
556
|
+
grep -r "eval(" pages/ components/ # Should be empty
|
|
557
|
+
grep -r "innerHTML =" pages/ components/ # Should only be in Shadow DOM
|
|
558
|
+
|
|
559
|
+
# Check Bun-native compliance
|
|
560
|
+
grep -r "fetch(" pages/ | grep -v "CORS" # Should all have headers
|
|
561
|
+
|
|
562
|
+
# Run test pyramid
|
|
563
|
+
bun test tests/unit/ # 70% should pass instantly
|
|
564
|
+
bun test tests/integration/ # 20% should pass in < 5s
|
|
565
|
+
bun test tests/e2e/ # 10% critical journeys
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## ๐ Resources
|
|
571
|
+
|
|
572
|
+
- **Framework API**: https://github.com/africode/framework
|
|
573
|
+
- **Bun Docs**: https://bun.sh/docs
|
|
574
|
+
- **Web Components**: https://developer.mozilla.org/en-US/docs/Web/Web_Components
|
|
575
|
+
- **NIDA CIG v2.1**: https://nida.go.tz/cig/docs
|
|
576
|
+
- **TIPS Standards**: https://tips.go.tz/standards
|
|
577
|
+
- **AML/FIU**: https://fiu.go.tz/reporting
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
**Last Reviewed**: May 2, 2026
|
|
582
|
+
**Next Review**: August 2, 2026 (quarterly)
|
|
583
|
+
**Contact**: framework@africode.dev
|