الـ Audit والـ Privacy Logs: سجّل مين عمل إيه، من غير ما تسجّل الأسرار

جارٍ التحميل…

01 / ملخص الدرس

الـ Audit والـ Privacy Logs: سجّل مين عمل إيه، من غير ما تسجّل الأسرار

API بيسجّل كل حاجة للـ debugging، فالـ logs بقى فيها الباسوردات وأرقام الكروت والـ tokens والـ cookies والإيميلات، وحد يقدر يحقن سطر مزيّف، ومحدش يعرف مين غيّر الـ roles. بنفهم الفرق بين الـ application log والـ audit log، و structured logging، و redaction للأسرار والـ PII، و log injection، و pseudonymization، و tamper-evident audit بـ hash chain، والاحتفاظ والـ retention. والتحدي: logger و audit قصاد سبعة وعشرين حالة.

02 / شرح الدرس مكتوبًا

نص شرح المعلم والكود الذي كتبه ونتيجة تشغيله، بنفس ترتيب الدرس.

أهلًا بيك. الـ logs حاجة كل الناس بتعملها، وقليل اللي بيعملها صح. المبرمج بيقول خليني أسجّل كل حاجة علشان لو حصلت مشكلة ألاقيها. وبعد كام شهر، يبقى عندك gigabytes من الـ logs فيها باسوردات العملاء وأرقام كروتهم و session cookies، وأي حد عنده access للـ logs، أو أي اختراق للـ log system، بقى معاه كل ده. وفيه حاجة تانية مختلفة خالص: الـ audit log. مش للـ debugging، ده سجل رسمي بـ مين عمل إيه: مين دخل، مين غيّر role حد لـ admin، مين وصل لـ data حساسة. ده اللي بيتسأل عنه في أي تحقيق أو compliance. server dot js بيعمل الغلطة الكلاسيكية: middleware بيسجّل كل request بالـ headers والـ body. attack dot js مش بيعمل أي هجوم، بيبعت requests عادية: login، ودفع، و login تاني بـ email غريب، وتغيير role. وبعدين بيقرا app dot log ويدوّر على الأسرار. نشغّل.

attack.js
// attack.js: requests عادية جدًا، وبعدين نشوف الـ logs فيها إيه
import { readFileSync, existsSync } from "node:fs";

const post = (path, body, headers = {}) =>
  fetch("http://localhost:3000" + path, {
    method: "POST",
    headers: { "content-type": "application/json", ...headers },
    body: JSON.stringify(body),
  });

await post("/login", { email: "[email protected]", password: "my-real-password-123" });
await post("/pay?token=tok_live_51Hx9", { card: "4242424242424242", cvv: "123", phone: "+201001234567" },
  { authorization: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1MSJ9.sig_lab", cookie: "sid=s3cr3t-session" });
// log injection: email فيه newline وسطر مزيّف
await post("/login", { email: "x\n2026-01-01T00:00:00.000Z admin login ok for [email protected]", password: "x" });
await post("/admin/users/u42/role", { role: "admin" }, { authorization: "Bearer admin_lab_token" });

const app = existsSync("app.log") ? readFileSync("app.log", "utf8") : "";
const leaks = ["my-real-password-123", "4242424242424242", "\"cvv\":\"123\"", "sid=s3cr3t-session", "Bearer eyJ", "tok_live_51Hx9",
  "[email protected]", "+201001234567"];
console.log(`app.log: ${app.split("\n").filter(Boolean).length} سطر`);
for (const s of leaks) console.log(app.includes(s) ? "☠ متسجّل:" : "✔ مش موجود:", s);
console.log(/\nadmin login ok|\n\S+ admin login ok/.test(app) ? "☠ فيه سطر مزيّف: admin login ok for ceo" : "✔ مفيش سطور مزيّفة");
const audit = existsSync("audit.log") ? readFileSync("audit.log", "utf8").trim() : "";
console.log(audit ? `✔ audit.log فيه ${audit.split("\n").length} سطر` : "☠ مفيش audit: مين خلّى u42 admin؟ محدش يعرف");if (audit) console.log("✔ آخر سطر في الـ audit:", JSON.parse(audit.split("\n").at(-1)).action, "← target", JSON.parse(audit.split("\n").at(-1)).target);

المخرجات

$ rm -f app.log audit.log; node server.js & S=$!; sleep 1; node attack.js; kill $S
API: http://localhost:3000
app.log: 7 سطر
☠ متسجّل: my-real-password-123
☠ متسجّل: 4242424242424242
☠ متسجّل: "cvv":"123"
☠ متسجّل: sid=s3cr3t-session
☠ متسجّل: Bearer eyJ
☠ متسجّل: tok_live_51Hx9
☠ متسجّل: [email protected]
☠ متسجّل: +201001234567
☠ فيه سطر مزيّف: admin login ok for ceo
☠ مفيش audit: مين خلّى u42 admin؟ محدش يعرف

كله متسجّل: الباسورد الحقيقي، ورقم الـ card كامل، والـ cvv، والـ session cookie، والـ Bearer token، والـ token اللي في الـ URL، والإيميلات، والموبايل. وأسوأ حاجة: سطر الـ login التاني. المهاجم حط newline في الـ email، وبعد الـ newline سطر شكله زي سطر log حقيقي بيقول admin login ok for ceo. ده اسمه log injection: لو حد بيقرا الـ logs بعينه أو بأداة، ممكن يتخض من سطر مش حصل أصلًا، أو يخبّي سطر حقيقي. وآخر حاجة: مين غيّر الـ user لـ admin؟ مفيش audit خالص. محدش يعرف.

نبدأ بالـ application log. أول حاجة: structured، يعني JSON سطر لكل event، مش نص حر. ده بيخلّي الـ newline يتحوّل لـ backslash n جُوّه الـ string، فمفيش حد يقدر يحقن سطر. وكمان بتقدر تعمل search و filter عليه. تاني: redaction. list بأسماء الـ fields الحساسة، وأي واحد فيهم القيمة بتتشال، مهما كان جايلك إزاي. وكمان scrub على الـ strings نفسها، علشان لو حد حط token جُوّه رسالة أو URL. تالت: ما تسجّلش الـ body والـ headers الخام أصلًا. سجّل اللي محتاجه بس: الـ method، والـ path، والـ status، والـ وقت، و request id تربط بيه كل سطور الـ request الواحد. رابع: الـ PII، يعني الـ data الشخصية زي الإيميل. بدل ما تسجّله، سجّل pseudonym: HMAC للـ id، فنفس الـ user بياخد نفس الرمز في كل السطور، وتقدر تتبّع سلوكه، من غير ما الإيميل نفسه يتسجّل.

والـ audit log حكاية تانية. كل سطر لازم فيه: مين، يعني الـ actor، عمل إيه، يعني الـ action، على مين أو إيه، يعني الـ target، والنتيجة، والوقت. وأهم حاجة فيه إنه tamper evident: لو حد عدّل أو مسح سطر، لازم يبان. إزاي؟ كل سطر بيحسب hash من محتواه زائد الـ hash بتاع السطر اللي قبله. فبيبقى زي سلسلة: تغيّر أي سطر، الـ hash بتاعه يتغيّر، فالسطر اللي بعده الـ prev بتاعه ما يطابقش، والسلسلة تتكسر عند أول تعديل بالضبط. ده نفس فكرة الـ blockchain، بس من غير أي تعقيد. في الإنتاج ممكن توقّع الـ hashes، أو تبعتها لـ system تاني write once، أو service زي CloudTrail. وحاجة مهمة قانونيًا: الـ retention. مش كل حاجة تتساب للأبد. الـ GDPR بيقول ما تخلّيش الـ PII عندك أكتر من اللازم. فالـ app logs عادة أيام لأسابيع، والـ audit logs أطول بكتير لأسباب قانونية، بس بالـ pseudonyms مش الـ data الخام.

server dot js الجديد بيستخدم logger dot js: access log منضّف بـ request id، و login بيسجّل userRef مش الإيميل، و payment بيعمل redact للـ body كله، وتغيير الـ role بيتكتب في الـ audit. التحدي: اكتب logger dot js: scrub و redact و userRef و createLogger و createAudit. test dot js فيه سبعة وعشرين حالة، منهم تعديل ومسح في الـ audit لازم verify يكشفهم.

تمرين

logger.js: scrub (Bearer و query tokens و كروت و emails و موبايل، والتواريخ سليمة)، و redact (keys حساسة بأي case، nested، من غير ما يغيّر الأصلي)، و userRef بـ HMAC، و createLogger JSON، و createAudit بـ hash chain و verify بيكشف أي تعديل.

الحل. scrub بـ كام replace، كل واحد لنوع: الـ Bearer، والـ query، والكروت، والإيميل، والموبايل. والترتيب مهم شوية. redact بتلف على الـ object، وبتعمل نسخة جديدة علشان ما تلمسش الأصلي، وبتحمي نفسها من العمق والـ circular. userRef بـ HMAC، فمحدش يقدر يرجع من الرمز للإيميل. والـ audit: كل سطر بياخد الـ prev، ويحسب hash، فالـ verify بيمشي على السلسلة ويقف عند أول كسر. خد بالك إني بعمل destructure للـ hash لوحده قبل ما أعيد حساب الـ sha، علشان أحسبه على نفس الحاجة اللي اتحسبت عليها الأول. نشغّل attack dot js تاني.

logger.js
// logger.js: logs منضّفة من الأسرار والـ data الشخصية، و audit log ما يتعدّلش من غير ما نعرف
import { appendFileSync, readFileSync, existsSync } from "node:fs";
import { createHash, createHmac } from "node:crypto";

// أسماء الـ keys اللي قيمتها ما تتسجّلش أبدًا (من غير حساسية للحروف الكبيرة، و - و _)
const SECRET_KEYS = new Set(["password", "passwd", "secret", "token", "accesstoken", "refreshtoken", "authorization",
  "cookie", "setcookie", "apikey", "xapikey", "card", "cardnumber", "cvv", "cvc", "otp", "pin"]);
const norm = (k) => k.toLowerCase().replace(/[-_]/g, "");

// قيم شكلها حساس جُوّه أي string
export function scrub(s) {
  return s
    .replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/g, "Bearer [REDACTED]")
    .replace(/([?&](?:token|key|secret|password|code)=)[^&#\s]*/gi, "$1[REDACTED]")
    .replace(/\b\d{13,19}\b/g, (d) => "****" + d.slice(-4))
    .replace(/([A-Za-z0-9._%+-])[A-Za-z0-9._%+-]*@([A-Za-z0-9.-]+\.[A-Za-z]{2,})/g, "$1***@$2")
    .replace(/\+\d[\d\s-]{7,}\d|\b01\d{9}\b/g, (p) => "***" + p.replace(/\D/g, "").slice(-2)); // +20... أو 01xxxxxxxxx
}

export function redact(value, depth = 0, seen = new WeakSet()) {
  if (typeof value === "string") return scrub(value);
  if (value === null || typeof value !== "object") return value;
  if (depth > 6) return "[DEPTH]";
  if (seen.has(value)) return "[CIRCULAR]";
  seen.add(value);
  if (Array.isArray(value)) return value.map((v) => redact(v, depth + 1, seen));
  const out = {};
  for (const [k, v] of Object.entries(value))
    out[k] = SECRET_KEYS.has(norm(k)) ? "[REDACTED]" : redact(v, depth + 1, seen);
  return out;
}

// نفس الـ user ← نفس الـ ref، بس من غير الـ email نفسه. الـ key في الإنتاج من الـ secret manager
export const userRef = (id, key = "lab-pseudonym-key") =>
  "u_" + createHmac("sha256", key).update(String(id).toLowerCase()).digest("hex").slice(0, 16);

// سطر JSON واحد لكل حدث في الـ app: الـ newlines بتبقى \n جُوّه الـ string، فمفيش log injection
export function createLogger(file) {
  return (level, msg, fields = {}) =>
    appendFileSync(file, JSON.stringify({ time: new Date().toISOString(), level, msg: scrub(String(msg)), ...redact(fields) }) + "\n");
}

// audit log: append-only، وكل سطر فيه hash السطر اللي قبله، فأي تعديل أو مسح بيبان
const sha = (s) => createHash("sha256").update(s).digest("hex");
const GENESIS = "0".repeat(64);

export function createAudit(file) {
  const lines = () => (existsSync(file) ? readFileSync(file, "utf8").split("\n").filter(Boolean) : []);
  let last = lines().at(-1);
  let prev = last ? JSON.parse(last).hash : GENESIS;

  return {
    record({ actor, action, target, result, ...extra }) {
      for (const [k, v] of Object.entries({ actor, action, target, result }))
        if (typeof v !== "string" || !v) throw new Error(`audit: ${k} لازم string`);
      const entry = { time: new Date().toISOString(), actor, action, target, result, ...redact(extra), prev };
      entry.hash = sha(JSON.stringify(entry));
      appendFileSync(file, JSON.s
…

المخرجات

$ rm -f app.log audit.log; node server.js & S=$!; sleep 1; node attack.js; kill $S
API: http://localhost:3000
app.log: 6 سطر
✔ مش موجود: my-real-password-123
✔ مش موجود: 4242424242424242
✔ مش موجود: "cvv":"123"
✔ مش موجود: sid=s3cr3t-session
✔ مش موجود: Bearer eyJ
✔ مش موجود: tok_live_51Hx9
✔ مش موجود: [email protected]
✔ مش موجود: +201001234567
✔ مفيش سطور مزيّفة
✔ audit.log فيه 3 سطر
✔ آخر سطر في الـ audit: user.role.change ← target u42

كله اتنضّف: مفيش باسورد ولا card ولا cookie ولا token ولا إيميل. ومفيش سطور مزيّفة، لأن الـ newline بقى جُوّه string. والـ audit فيه مين غيّر الـ role. ونشغّل test dot js.

logger.js

المخرجات

$ rm -f app.log audit.log; node server.js & S=$!; sleep 1; node test.js; kill $S
API: http://localhost:3000
✅ Bearer token ← REDACTED 
✅ ?token= في الـ URL ← REDACTED وباقي الـ query زي ما هو 
✅ &password= و ?code= 
✅ رقم كارت ← آخر أربعة 
✅ email ← أول حرف و الـ domain 
✅ موبايل دولي ← آخر رقمين 
✅ موبايل مصري 01 
✅ التاريخ والـ UUID ما يتلمسوش 
✅ رقم عادي قصير ما يتلمسش 
✅ keys حساسة بأي case أو - أو _ ← REDACTED 
✅ nested و arrays 
✅ الأرقام زي ما هي، والـ strings بتتعمل scrub 
✅ circular ما يعملش crash 
✅ redact ما بيغيّرش الـ object الأصلي 
✅ userRef ثابت لنفس الـ user ومن غير case 
✅ userRef مختلف لـ users مختلفين، وما فيهوش الـ email 
✅ سطر واحد بس حتى لو فيه newline (مفيش log injection) 
✅ الـ log JSON فيه time و level و msg 
✅ الـ fields متنضّفة 
✅ record بيرجّع entry فيه prev و hash 
✅ الـ extra بيتعمل له redact 
✅ verify على log سليم ← ok و count تلاتة 
✅ record من غير actor ← throw 
✅ audit جديد على نفس الـ file بيكمّل الـ chain 
✅ تعديل سطر ← verify بيقول سطر واحد 
✅ مسح سطر من النص ← verify بيقول سطر اتنين 
✅ سطر زبالة ← ok false من غير throw 

27/27 نجحوا

كله نجح، بما فيه إن verify كشف لما عدّلنا سطر، ولما مسحنا سطر من النص. في الإنتاج: pino أو مكتبة شبهها بتعمل الـ structured logging والـ redaction بسرعة، وبتبعت الـ logs لـ system زي Loki أو Elasticsearch أو Datadog، والـ audit لـ store منفصل. بس المبادئ واحدة: نضّف قبل ما تكتب، مش بعد. الدرس الجاي، AppSec testing و OWASP ASVS. إزاي تحط الأمن في الـ CI نفسه، و SAST و DAST و dependency scanning، و ASVS كـ checklist تمشي عليها.

server.js
// server.js: نفس الـ API، بس بـ logger منضّف و audit لكل حاجة مهمة
import express from "express";
import { randomUUID } from "node:crypto";
import { createLogger, createAudit, userRef } from "./logger.js";

const app = express();
app.use(express.json());
const log = createLogger("app.log");
const audit = createAudit("audit.log");

app.use((req, res, next) => {
  req.id = randomUUID();
  const t = Date.now();
  // الـ access log: مفيش body ومفيش headers، بس اللي محتاجينه للـ debugging
  res.on("finish", () => log("info", "request", { id: req.id, method: req.method, url: req.originalUrl, status: res.statusCode, ms: Date.now() - t }));
  next();
});

app.post("/login", (req, res) => {
  const { email, password } = req.body;
  const ok = password === "correct horse";
  // في الـ app.log: userRef مش الـ email. وفي الـ audit: الـ actor هو الـ ref برضه
  log(ok ? "info" : "warn", "login", { id: req.id, user: userRef(email), ok });
  audit.record({ actor: userRef(email), action: "auth.login", target: "self", result: ok ? "success" : "failure", ip: req.ip, requestId: req.id });
  if (!ok) return res.status(401).json({ error: "غلط" });
  res.json({ token: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1MSJ9.sig_lab" });
});

app.post("/pay", (req, res) => {
  log("info", "payment", { id: req.id, ...req.body }); // حتى لو حد بعت الـ body كله، redact بيضبطه
  res.json({ ok: true, last4: String(req.body.card).slice(-4) });
});

app.post("/admin/users/:id/role", (req, res) => {
  const actor = "admin_1"; // في الحقيقة من الـ session
  audit.record({ actor, action: "user.role.change", target: req.params.id, result: "success", to: req.body.role, ip: req.ip, requestId: req.id });
  res.json({ id: req.params.id, role: req.body.role });
});

app.listen(3000, () => console.log("API: http://localhost:3000"));
test.js
import { readFileSync, writeFileSync, rmSync } from "node:fs";
import { scrub, redact, userRef, createLogger, createAudit } from "./logger.js";

let ok = 0, all = 0;
const check = (name, cond, extra = "") => { all++; if (cond) ok++; console.log(cond ? "✅" : "❌", name, extra); };

check("Bearer token ← REDACTED", scrub("auth Bearer eyJhbGc.x.y ok") === "auth Bearer [REDACTED] ok");
check("?token= في الـ URL ← REDACTED وباقي الـ query زي ما هو", scrub("/pay?token=tok_1&amount=5") === "/pay?token=[REDACTED]&amount=5");
check("&password= و ?code=", scrub("/cb?code=abc&x=1&password=p") === "/cb?code=[REDACTED]&x=1&password=[REDACTED]");
check("رقم كارت ← آخر أربعة", scrub("card 4242424242424242 done") === "card ****4242 done");
check("email ← أول حرف و الـ domain", scrub("hi [email protected]") === "hi m***@baassma.tech");
check("موبايل دولي ← آخر رقمين", scrub("call +20 100 123 4567") === "call ***67");
check("موبايل مصري 01", scrub("01001234567") === "***67");
const iso = "2026-01-01T10:00:00Z 3f2b9c1e-1111-4a2b-9c3d-123456789abc";
check("التاريخ والـ UUID ما يتلمسوش", scrub(iso) === iso);
check("رقم عادي قصير ما يتلمسش", scrub("amount 15000 ms 12") === "amount 15000 ms 12");

const r = redact({ password: "p", Password: "p", api_key: "k", "X-Api-Key": "k", nested: { Authorization: "Bearer x", list: [{ cvv: "1" }] }, amount: 5, note: "mail [email protected]" });
check("keys حساسة بأي case أو - أو _ ← REDACTED", r.password === "[REDACTED]" && r.Password === "[REDACTED]" && r.api_key === "[REDACTED]" && r["X-Api-Key"] === "[REDACTED]");
check("nested و arrays", r.nested.Authorization === "[REDACTED]" && r.nested.list[0].cvv === "[REDACTED]");
check("الأرقام زي ما هي، والـ strings بتتعمل scrub", r.amount === 5 && r.note === "mail a***@b.co");
const circ = { a: 1 }; circ.self = circ;
check("circular ما يعملش crash", (() => { try { return redact(circ).self === "[CIRCULAR]"; } catch { return false; } })());
const orig = { password: "p" }; redact(orig);
check("redact ما بيغيّرش الـ object الأصلي", orig.password === "p");
check("userRef ثابت لنفس الـ user ومن غير case", userRef("[email protected]") === userRef("[email protected]") && /^u_[0-9a-f]{16}$/.test(userRef("a")));
check("userRef مختلف لـ users مختلفين، وما فيهوش الـ email", userRef("[email protected]") !== userRef("[email protected]") && !userRef("[email protected]").includes("@"));

rmSync("t-app.log", { force: true });
const log = createLogger("t-app.log");
log("warn", "login failed for x\n2026 admin login ok", { email: "[email protected]", password: "pw" });
const lines = readFileSync("t-app.log", "utf8").trim().split("\n");
check("سطر واحد بس حتى لو فيه newline (مفيش log injection)", lines.length === 1);
const j = JSON.parse(lines[0]);
check("الـ log JSON فيه time و level و msg", !!j.time && j.level === "warn" && j.msg.includes("login failed"));
check("الـ fields متنضّفة", j.password === "[REDACTED]" && j.email === "z***@q.io");

rmSync("t-audit.log", { force: true });
const a = createAudit("t-audit.log");
const e1 = a.record({ actor: "admin_1", actio
…
03 / دروس المسار (122)
  1. 01أهلًا بيك: يعني إيه backend، والكورس ده ماشي إزاي
  2. 02الملفات والفولدرات والـ terminal: تتحرك على جهازك زي المبرمجين
  3. 03Node وأول برنامج: تشغّل وتقرا رسالة الخطأ
  4. 04القيم والمتغيرات والأنواع: const و let و typeof
  5. 05القرارات والتكرار: if و === والـ truthy والـ loops
  6. 06الـ functions: parameters و return والـ arrow functions والـ scope
  7. 07الـ objects والـ arrays: destructuring و spread و map و filter و reduce
  8. 08JSON والنصوص والتواريخ: اللغة اللي الـ backend بيتكلم بيها
  9. 09الـ callbacks والـ closures وأول لمسة async: setTimeout
  10. 10الـ classes والـ errors: throw و try/catch و stack trace
  11. 11git: تحفَظ كل خطوة وترجعلها، وما تسرّبش أسرارك
  12. 12ESM و CommonJS و package exports: Node بيلاقي الـ modules إزاي
  13. 13الـ Promises و async/await: sequential و parallel والأخطاء والإلغاء
  14. 14الـ event loop والـ microtasks: Node بيعمل كل حاجة بـ thread واحد إزاي
  15. 15الـ Streams والـ Backpressure: ملفات أكبر من الـ memory
  16. 16الـ File System والـ paths: قراية وكتابة صح، ومن غير path traversal
  17. 17الـ Buffers والبيانات الـ binary: الـ bytes من جُوّه
  18. 18Crypto APIs والأسرار: random و hash و HMAC و AES-GCM
  19. 19الـ Worker Threads: شغل CPU تقيل من غير ما توقف الـ server
  20. 20الـ Errors على مستوى الـ process: operational و programmer و crash-only
  21. 21الـ Node test runner والـ debugging: tests من غير مكتبات
  22. 22HTTP من جُوّه: الـ methods والـ status codes والـ headers
  23. 23Express والـ Routing: الـ params والـ query والترتيب والـ Router
  24. 24Express 5: إيه اللي اتغيّر، وإزاي تنقل مشروع قديم
  25. 25الـ Middleware ودورة حياة الـ request جُوّه Express
  26. 26Validation للمدخلات بـ Zod: ما تصدّقش أي حاجة جاية من برة
  27. 27تصنيف الأخطاء و Problem Details: شكل واحد لكل الـ errors
  28. 28الـ CORS والـ Cookies: المتصفح بيحمي المستخدم إزاي
  29. 29رفع الملفات وحدود الحجم: multer من غير ثغرات
  30. 30الـ Realtime: Server-Sent Events و WebSockets
  31. 31OpenAPI والـ API Versioning: عقد مكتوب، وتغيير من غير ما تكسر حد
  32. 32PostgreSQL: الـ DDL وأنواع البيانات الصح لكل عمود
  33. 33الـ Constraints: PK و FK و UNIQUE و CHECK — الـ database بتحمي نفسها
  34. 34الـ Normalization والـ ERD: تقسّم البيانات صح من أول يوم
  35. 35الـ JOINs والتجميع: INNER و LEFT و GROUP BY و HAVING و window functions
  36. 36JSONB في PostgreSQL: إمتى تستخدمه، وإزاي تسأله وتعمله index
  37. 37الـ Indexes من جُوّه: B-tree و GIN و BRIN
  38. 38Partial و Covering indexes: indexes أصغر وأسرع
  39. 39الـ Pagination بالـ Keyset: ليه OFFSET بيبطّأ وبيكرر
  40. 40Full Text Search في Postgres: بحث بالكلمات، بالعربي والإنجليزي
  41. 41EXPLAIN ANALYZE والـ Planner: اقرا الـ plan وصلّح الـ query
  42. 42الـ Transactions بـ node-postgres: كله أو ولا حاجة
  43. 43الـ MVCC ومستويات الـ Isolation: transactions كتير في نفس الوقت
  44. 44الـ Locks والـ Deadlocks: مين مستني مين
  45. 45SKIP LOCKED و Job Leasing: Postgres كـ job queue
  46. 46Row Level Security والـ Multi-tenancy: كل عميل يشوف بياناته بس
  47. 47Migrations من غير downtime: expand و backfill و contract
  48. 48الـ Replication والـ Read Replicas: نسخ حية من الـ database
  49. 49الـ Connection Pooling و PgBouncer: connections أقل، requests أكتر
  50. 50الـ Partitioning والـ VACUUM والمراقبة: Postgres على المدى الطويل
  51. 51Redis وأنواع البيانات: strings و hashes و lists و sets و sorted sets
  52. 52Cache-aside والـ TTL: Redis قدام الـ database
  53. 53الـ Cache invalidation والـ Stampede: لما الـ key الشهير يموت
  54. 54Lua والـ Atomicity في Redis: كام أمر كأنهم أمر واحد
  55. 55الـ Rate Limiting في Redis: fixed window و sliding window و token bucket
  56. 56الـ Sessions في Redis: تسجيل دخول تقدر تلغيه في أي وقت
  57. 57Redis Streams والـ Consumer Groups: log بيتوزع على workers
  58. 58Pub/Sub و BullMQ: إشارات بين الـ instances، وطوابير شغل محترمة
  59. 59Redis لما يقع: الـ persistence (RDB و AOF) والـ replication
  60. 60Redis في الإنتاج: الـ ACLs والـ Cluster والمراقبة
  61. 61تخزين الـ Passwords بـ Argon2id: صح من أول مرة
  62. 62Session Fixation والـ Rotation: id جديد مع كل صلاحية جديدة
  63. 63الـ Cookie Flags والـ CSRF: المتصفح بيبعت الـ cookie، فلازم تتأكد مين اللي طلب
  64. 64الـ XSS والـ Content Security Policy: ما تخليش النص يتحوّل لـ code
  65. 65الـ OAuth و OpenID Connect و PKCE: login بـ Google من غير ما تشوف الـ password
  66. 66التأكد من الـ JWT صح: التوقيع والـ claims والـ scopes
  67. 67الـ BOLA و BFLA: الـ token السليم مش معناه إن الطلب مسموح
  68. 68الـ RBAC و ABAC والملكية: policy واحدة بدل ifs متفرقة
  69. 69الـ MFA والـ recovery: التاني factor اللي بجد
  70. 70الـ Passkeys و WebAuthn: login من غير password وضد الـ phishing
  71. 71الـ Threat Modeling بـ STRIDE: فكّر زي المهاجم قبل ما تكتب code
  72. 72الـ SQL Injection والـ Parameterization: الـ data ما تبقاش code
  73. 73الـ SSRF والـ Egress: ما تخليش الـ server بتاعك يزور الشبكة الداخلية
  74. 74الـ Security Headers والـ TLS: كل response يقول للـ browser يحمي المستخدم إزاي
  75. 75توقيع الـ Webhooks والـ Replay: الـ webhook ده جاي فعلًا من Stripe؟
  76. 76تغيير الأسرار والـ HMAC: إزاي تغيّر مفتاح من غير ما كل حاجة تقع
  77. 77سلسلة التوريد والـ SBOM: إنت واثق في ألف package ما تعرفهمش؟
  78. 78الـ Audit والـ Privacy Logs: سجّل مين عمل إيه، من غير ما تسجّل الأسرارانت هنا
  79. 79اختبار الأمان و OWASP ASVS: الأمن جُوّه الـ CI، مش audit آخر السنة
  80. 80الـ Prototype Pollution والـ Resource DoS: request واحد يخلّي الكل admin أو يوقّع الـ server
  81. 81الـ SLI والـ SLO والـ Error Budget: إمتى تصحّي الـ on-call وإمتى تسيبه نايم
  82. 82الـ Event Loop Delay والـ ELU: لما Node نفسه يتخنق
  83. 83الـ Worker Threads والـ CPU Profiling: الشغل التقيل بره الـ event loop، والوقت راح فين
  84. 84الـ Memory والـ GC والـ Leaks: الـ process اللي بيكبر لحد ما يقع
  85. 85الـ N+1 Queries والـ DataLoader: صفحة واحدة بمِيّتين query
  86. 86الـ HTTP Caching والـ Compression: أسرع request هو اللي ما بيوصلش
  87. 87الـ Load Testing والـ Soak Testing: الـ server بيستحمل قد إيه بجد
  88. 88الـ Concurrency Limits والـ Bulkheads: dependency بطيئة ما توقعش الـ app كله
  89. 89الـ Timeouts والـ Retries والـ Circuit Breakers: إزاي تتعامل مع dependency بطيئة أو واقعة
  90. 90OpenTelemetry والـ Distributed Tracing: الـ request راح فين وضاع وقته فين
  91. 91Docker Layers والـ Build Context: ليه الـ build بياخد دقيقة وفيه الـ .env بتاعك
  92. 92Multi-stage Builds و Non-root: image صغيرة ومن غير root
  93. 93Docker Compose والـ Networks: الـ services بتلاقي بعض إزاي
  94. 94Docker Volumes: الـ data بتتحفَظ فين
  95. 95Healthcheck و Restart و Resource Limits: running مش معناها شغّال
  96. 96BuildKit والـ Build Secrets: الـ token ما يدخلش الـ image
  97. 97Reverse Proxy و TLS: اللي واقف قدام الـ app
  98. 98Multi-arch Images والـ Native Modules: اشتغلت عندي
  99. 99CI/CD و Rollback و Canary: الـ deploy يبقى ممل
  100. 100Kubernetes من الأول: Pods و Deployments و Services و Probes
  101. 101Modular Monolith و DDD: حدود واضحة من غير network
  102. 102Transactional Outbox و Inbox: الـ event ما يضيعش وما يتنفذش مرتين
  103. 103Sagas: عملية واحدة على تلات services من غير transaction واحدة
  104. 104CQRS و Event Sourcing: الـ events هي الحقيقة
  105. 105الـ Queues والـ Brokers: BullMQ و RabbitMQ و Kafka و SQS
  106. 106Realtime على أكتر من instance: Redis pub/sub و presence و resume
  107. 107الـ Object Storage والـ Media: presigned URLs و uploads مباشرة
  108. 108التكامل مع الـ Email والـ Search: retries و webhooks و indexes
  109. 109GraphQL و gRPC في الإنتاج: contracts و DataLoader و limits و deadlines
  110. 110Kafka على أكتر من zone و region: الـ replication والـ ISR والـ acks والـ MirrorMaker والـ failover
  111. 111TypeScript و runtime boundaries: الـ types بتختفي، والـ schemas لأ
  112. 112ORM ولا SQL: query builders و repositories و migrations و transactions
  113. 113الـ Serverless من جُوّه: cold starts و freeze و timeouts و connections
  114. 114الـ Testing Pyramid: unit و integration و e2e على Postgres حقيقية
  115. 115Contract Testing و Property-Based Testing بـ fast-check
  116. 116الـ Payments: idempotency و webhooks و refunds و reconciliation
  117. 117الـ Timezones والـ Internationalization: UTC و DST والـ locales والـ plurals والفلوس
  118. 118الـ Privacy والـ Data Retention: consent و export و erasure و crypto shredding
  119. 119الـ ADRs والـ Feature Flags: القرارات المكتوبة والـ rollout من غير deploy
  120. 120Multi-region active-active: حل الـ conflicts بـ HLC و CRDTs
  121. 121Readiness و Liveness و Startup Probes: الـ pod جاهز ولا عايش؟
  122. 122Incident Runbooks: من الـ alert للـ postmortem