E-commerce tenun Nusantara (tenun ikat, songket, endek Bali) — bahasa Tenun, kerangka Jala (MVC), struktur ala Laravel. PostgreSQL (via ORM) + Redis (sesi/keranjang) + live chat WebSocket. UI Bootstrap 5 + jQuery + DataTables, responsif.
- Etalase: katalog, filter kategori, pencarian, detail produk.
- Keranjang (Redis) + checkout + halaman sukses.
- Akun: daftar/masuk/keluar (sandi PBKDF2; sesi di Redis).
- Admin: dashboard (omzet/jumlah), kelola produk (DataTables + tambah/hapus), pesanan (DataTables), live chat.
- Live chat WebSocket (widget pelanggan + panel admin).
- PostgreSQL + Redis berjalan (default
127.0.0.1:5432/:6379). - Buat database:
createdb toko_tenun(atauCREATE DATABASE toko_tenun;). - Kredensial via env (default lokal):
PGHOST PGPORT PGUSER PGPASSWORD PGDATABASE REDIS_HOST REDIS_PORT.
tenun add jala # web, tampilan, auth
tenun add orm # postgres, mysql
tenun add redis
tenun add websocket
tenun database/Migrasi.tenun # buat tabel
tenun tools/scrape.tenun # (opsional) scraper lama; produk.csv kini berisi 30 produk tenun
tenun database/Seeder.tenun # isi produk (dari produk.csv) + admin
# Web + live chat jadi SATU proses (WebSocket di port yang sama, 8080):
TENUN_WORKERS=1 tenun
# Linux server: live chat broadcast jalan penuh dalam 1 proses (soket blocking biasa).
# Multi-proses (di belakang Nginx): fan-out chat antar-instance via Redis Pub/Sub (lihat Skala).
# Catatan: di Windows dev, broadcast antar-klien terbatas (kuirk IOCP std.net) — pakai Linux untuk produksi.
# atau:
powershell -ExecutionPolicy Bypass -File tools/start.ps1 # Windows
bash tools/start.sh # Linux/macOS
Admin: admin@toko.id / admin123.
TENUN_WORKERS=1: tiap proses memakai 1 worker karena memegang koneksi soket (DB/Redis) sendiri. Skalakan dengan menjalankan banyak proses di belakang load balancer (lihat di bawah), bukan banyak thread satu proses.
index.tenun bootstrap (entry; `tenun` menjalankan ini)
chat.tenun server live chat WebSocket
config/
app.tenun nama app, ws_url, folder view
database.tenun koneksi Postgres+Redis (env), db_init()
routes/
web.tenun rute + grup (/admin, /api)
app/
Http/Controllers/ Home, Keranjang, Checkout, Auth, Admin
Http/Middleware/Keamanan.tenun header keamanan, CSRF, rate-limit, escape XSS
Models/ Produk, Pengguna, Pesanan (SKEMA ORM saja)
Services/Cart.tenun keranjang (Redis)
Support/Helper.tenun sesi (Redis), pengguna, rupiah, sajikan()
database/
Migrasi.tenun Seeder.tenun runner
migrations/ 01_produk, 02_pengguna, 03_pesanan
seeders/ ProdukSeeder, PenggunaSeeder
resources/views/ Batik (layout, partials, home, keranjang, checkout, auth, admin)
public/ style.css, app.js
Model = definisi skema saja; query ada di controller (via ORM/qb). Seeder & migrasi terpisah di database/.
Lapisan keamanan didaftarkan global di index.tenun via jala_pakai(...) (lihat app/Http/Middleware/Keamanan.tenun):
- Header keamanan tiap respons:
Content-Security-Policy(object/base/frame dikunci),X-Content-Type-Options: nosniff,X-Frame-Options: DENY,Referrer-Policy,Permissions-Policy. - CSRF: semua metode pengubah-state (POST/PUT/DELETE/PATCH) wajib token
_csrfvalid (token stabil per sesi, disisipkan tiap<form>via{{csrf}}). Tanpa token → 419. - Rate-limit login/daftar: 10 percobaan/menit/IP (Redis), cegah brute force → 429.
- Anti XSS: helper
aman()meng-escape semua data tak-tepercaya (nama produk, input pencarian, nama pengguna) sebelum masuk HTML. Cookie sesisiddiperkerasHttpOnly; SameSite=Lax. - Path traversal: jalur memuat
..ditolak (400). - Sandi di-hash (modul
auth,auth_hash/auth_verifikasi), bukan plaintext.
Di balik HTTPS (nginx), tambah ; Secure pada cookie. Sisa yang perlu diperketat: /keranjang/hapus/:id masih GET (idealnya POST + CSRF); template Batik render mentah secara default (mengandalkan aman() di sisi controller) — pilihan jangka panjang: jadikan escape default di modul jala/tampilan.
Model proses stateless (mirip PHP-FPM):
[ CDN ] (aset statis)
|
[ Nginx / Load Balancer ]
| | |
tenun:8081 tenun:8082 ... (N proses, TENUN_WORKERS=1, stateless)
\ | /
[ Redis ] sesi, keranjang, cache, rate-limit, pubsub chat
|
[ PostgreSQL + read-replica ]
- Stateless: sesi/keranjang di Redis, jadi request mana pun bisa dilayani proses mana pun.
- Scale-out: jalankan banyak proses
TENUN_WORKERS=1di port berbeda; Nginxupstreamround-robin. Tambah proses = tambah kapasitas (k8s: replika pod). - DB: index pada kolom yang difilter; read-replica untuk query berat.
- Cache:
redis_setex("cache:produk", 60, ...); rate-limit:redis_batas(...). - Live chat: untuk banyak instance, fan-out via Redis Pub/Sub (publish lalu tiap instance
ws_siar).
MIT.