-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinterview-quick-fire.html
More file actions
960 lines (924 loc) · 171 KB
/
Copy pathinterview-quick-fire.html
File metadata and controls
960 lines (924 loc) · 171 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interview Quick-Fire — Patterns & Diagrams</title>
<meta name="description" content="System design quick-fire — severity-coded patterns plus 17 interactive Mermaid diagrams, offline.">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='6' fill='%23185fa5'/><text x='16' y='22' text-anchor='middle' fill='white' font-size='14' font-family='sans-serif' font-weight='700'>SD</text></svg>">
<style>
:root{
--bg:#f7f6f3;--card:#fff;--text:#37352f;--muted:#787774;
--critical-bg:#fdebec;--critical-bdr:#e16259;--critical-txt:#7f1d1d;
--high-bg:#fbf3db;--high-bdr:#d9a006;--high-txt:#713f12;
--important-bg:#f3e8ff;--important-bdr:#9065b0;--important-txt:#581c87;
--pattern-bg:#edf3ec;--pattern-bdr:#448361;--pattern-txt:#1a3d2a;
--prep-bg:#e7f3f8;--prep-bdr:#337ea9;--prep-txt:#0c4a6e;
--font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
--mono:ui-monospace,SFMono-Regular,Menlo,monospace;
--r:10px;
}
html[data-theme="dark"]{
--bg:#191919;--card:#252525;--text:#e3e2de;--muted:#9b9a97;
--critical-bg:#3d1f1f;--critical-bdr:#e16259;--critical-txt:#fecaca;
--high-bg:#3d3018;--high-bdr:#d9a006;--high-txt:#fde68a;
--important-bg:#2e1f3d;--important-bdr:#9065b0;--important-txt:#e9d5ff;
--pattern-bg:#1f2e22;--pattern-bdr:#448361;--pattern-txt:#bbf7d0;
--prep-bg:#1a2a33;--prep-bdr:#337ea9;--prep-txt:#bae6fd;
}
@media(prefers-color-scheme:dark){
html:not([data-theme="light"]){
--bg:#191919;--card:#252525;--text:#e3e2de;--muted:#9b9a97;
--critical-bg:#3d1f1f;--critical-bdr:#e16259;--critical-txt:#fecaca;
--high-bg:#3d3018;--high-bdr:#d9a006;--high-txt:#fde68a;
--important-bg:#2e1f3d;--important-bdr:#9065b0;--important-txt:#e9d5ff;
--pattern-bg:#1f2e22;--pattern-bdr:#448361;--pattern-txt:#bbf7d0;
--prep-bg:#1a2a33;--prep-bdr:#337ea9;--prep-txt:#bae6fd;
}
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:var(--font);background:var(--bg);color:var(--text);line-height:1.55}
a{color:var(--prep-bdr)}
.app{display:flex;min-height:100vh}
.content-area{flex:1;min-width:0;display:flex;flex-direction:column}
.view-shell{display:none;flex:1;min-height:0}
.view-shell.view-active{display:block}
.view-diagrams.view-active{display:flex;flex-direction:column}
.view-diagrams.view-active .diag-app{height:100vh}
.sidebar{width:280px;background:var(--card);border-right:1px solid rgba(0,0,0,.08);padding:16px 12px;position:sticky;top:0;height:100vh;overflow-y:auto;flex-shrink:0}
.view-tabs{display:flex;gap:6px;margin-bottom:14px}
.view-tabs .vtab{flex:1;font-size:.78rem;font-weight:600;padding:7px 10px;border-radius:8px;border:1px solid rgba(0,0,0,.1);background:var(--bg);color:var(--muted);cursor:pointer}
.view-tabs .vtab.on{background:var(--prep-bg);border-color:var(--prep-bdr);color:var(--prep-txt)}
.main{flex:1;max-width:920px;padding:28px 32px 80px}
.diag-link{font-weight:500}
h1{font-size:1.75rem;margin-bottom:8px;letter-spacing:-.02em}
.hero-sub{color:var(--muted);font-size:1rem;margin:-2px 0 14px}
.lead p{color:var(--muted);margin-bottom:12px;font-size:.95rem;line-height:1.6}
.hero-links{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 20px}
.hero-links a{font-size:.82rem;padding:5px 12px;border-radius:100px;border:1px solid rgba(0,0,0,.1);background:var(--card);text-decoration:none;color:var(--text);font-weight:500}
.hero-links a:hover{border-color:var(--prep-bdr);color:var(--prep-bdr)}
.legend{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px;margin:20px 0 28px}
.leg{padding:10px 12px;border-radius:var(--r);border-left:4px solid;font-size:.8rem;font-weight:600}
.leg small{display:block;font-weight:400;color:var(--muted);margin-top:2px;font-size:.72rem}
.leg.critical{background:var(--critical-bg);border-color:var(--critical-bdr);color:var(--critical-txt)}
.leg.high{background:var(--high-bg);border-color:var(--high-bdr);color:var(--high-txt)}
.leg.important{background:var(--important-bg);border-color:var(--important-bdr);color:var(--important-txt)}
.leg.pattern{background:var(--pattern-bg);border-color:var(--pattern-bdr);color:var(--pattern-txt)}
.leg.prep{background:var(--prep-bg);border-color:var(--prep-bdr);color:var(--prep-txt)}
.toolbar{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:24px;align-items:center}
.toolbar input{flex:1;min-width:180px;padding:8px 12px;border-radius:8px;border:1px solid rgba(0,0,0,.12);background:var(--card);color:var(--text)}
.fchip{font-size:.75rem;padding:5px 12px;border-radius:100px;border:1px solid rgba(0,0,0,.1);background:var(--card);cursor:pointer}
.fchip.on{font-weight:600}
.fchip.critical.on{background:var(--critical-bg);border-color:var(--critical-bdr);color:var(--critical-txt)}
.fchip.high.on{background:var(--high-bg);border-color:var(--high-bdr);color:var(--high-txt)}
.fchip.important.on{background:var(--important-bg);border-color:var(--important-bdr);color:var(--important-txt)}
.fchip.pattern.on{background:var(--pattern-bg);border-color:var(--pattern-bdr);color:var(--pattern-txt)}
.fchip.prep.on{background:var(--prep-bg);border-color:var(--prep-bdr);color:var(--prep-txt)}
.tb{font-size:.8rem;padding:6px 12px;border-radius:8px;border:1px solid rgba(0,0,0,.1);background:var(--card);cursor:pointer;color:var(--muted)}
.sec{margin-bottom:36px}
.sec-hdr{display:flex;align-items:center;gap:10px;margin-bottom:14px;padding:12px 16px;border-radius:var(--r);font-size:1.05rem;font-weight:700}
.sec-hdr.critical{background:var(--critical-bg);color:var(--critical-txt);border:1px solid var(--critical-bdr)}
.sec-hdr.high{background:var(--high-bg);color:var(--high-txt);border:1px solid var(--high-bdr)}
.sec-hdr.important{background:var(--important-bg);color:var(--important-txt);border:1px solid var(--important-bdr)}
.sec-hdr.pattern{background:var(--pattern-bg);color:var(--pattern-txt);border:1px solid var(--pattern-bdr)}
.sec-hdr.prep{background:var(--prep-bg);color:var(--prep-txt);border:1px solid var(--prep-bdr)}
.card{background:var(--card);border-radius:var(--r);margin-bottom:12px;overflow:hidden;border:1px solid rgba(0,0,0,.06);box-shadow:0 1px 2px rgba(0,0,0,.04)}
.card-hdr{display:flex;align-items:center;gap:10px;padding:14px 16px;cursor:pointer;user-select:none}
.card-hdr:hover{background:rgba(0,0,0,.02)}
.badge{font-size:.7rem;font-weight:700;padding:3px 8px;border-radius:6px;white-space:nowrap}
.badge.critical{background:var(--critical-bg);color:var(--critical-txt);border:1px solid var(--critical-bdr)}
.badge.high{background:var(--high-bg);color:var(--high-txt);border:1px solid var(--high-bdr)}
.badge.important{background:var(--important-bg);color:var(--important-txt);border:1px solid var(--important-bdr)}
.badge.pattern{background:var(--pattern-bg);color:var(--pattern-txt);border:1px solid var(--pattern-bdr)}
.badge.prep{background:var(--prep-bg);color:var(--prep-txt);border:1px solid var(--prep-bdr)}
.card-title{font-weight:600;font-size:.95rem;flex:1}
.card-chev{color:var(--muted);transition:transform .15s}
.card.open .card-chev{transform:rotate(90deg)}
.card-body{display:none;border-top:1px solid rgba(0,0,0,.06)}
.card.open .card-body{display:block}
.callout{margin:12px 16px;padding:12px 14px;border-radius:8px;border-left:4px solid;font-size:.88rem;line-height:1.65}
.callout strong{display:block;margin-bottom:4px;font-size:.72rem;text-transform:uppercase;letter-spacing:.04em;opacity:.85}
.callout.critical{background:var(--critical-bg);border-color:var(--critical-bdr)}
.callout.high{background:var(--high-bg);border-color:var(--high-bdr)}
.callout.important{background:var(--important-bg);border-color:var(--important-bdr)}
.callout.pattern{background:var(--pattern-bg);border-color:var(--pattern-bdr)}
.callout.prep{background:var(--prep-bg);border-color:var(--prep-bdr)}
.callout.problem{background:var(--prep-bg);border-color:var(--prep-bdr);font-style:italic}
.qf-java-wrap{margin:10px 0 0}
.qf-java-label{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--prep-bdr);margin:14px 0 6px}
.qf-java-wrap .qf-java-label:first-child{margin-top:0}
.qf-java{font-family:var(--mono);font-size:.72rem;line-height:1.55;background:rgba(0,0,0,.06);border:1px solid rgba(0,0,0,.08);padding:12px 14px;margin:0 0 10px;border-radius:8px;overflow-x:auto;white-space:pre;color:var(--text);tab-size:4}
.qf-java:last-child{margin-bottom:0}
.qf-java code{font-family:inherit;font-size:inherit;background:none;padding:0;border-radius:0;display:block}
html[data-theme="dark"] .qf-java{background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.1)}
.visual{margin:0 16px 14px;font-size:.82rem;color:var(--muted)}
.visual a{font-weight:500}
.sb-link{display:block;padding:5px 10px;font-size:.8rem;color:var(--muted);text-decoration:none;border-radius:6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sb-link:hover{background:rgba(0,0,0,.04);color:var(--text)}
.sb-group{margin-bottom:6px}
.sb-sec-link{display:flex;align-items:center;justify-content:space-between;gap:6px;font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);padding:10px 8px 4px;text-decoration:none;border-radius:6px;cursor:pointer}
.sb-sec-link:hover{background:rgba(0,0,0,.04);color:var(--text)}
.sb-count{font-size:.62rem;font-weight:600;padding:1px 6px;border-radius:100px;background:rgba(0,0,0,.06);color:var(--muted);flex-shrink:0}
.sb-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}
.links{margin-top:16px;font-size:.85rem}
.links a{margin-right:12px}
code{font-family:var(--mono);font-size:.85em;background:rgba(0,0,0,.06);padding:1px 5px;border-radius:4px}
@media(max-width:768px){
.app{display:block}
.sidebar{position:relative;height:auto;width:100%;border-right:none;border-bottom:1px solid rgba(0,0,0,.08)}
.main{padding:20px 16px}
.view-diagrams.view-active .diag-app{height:auto;min-height:calc(100vh - 0px)}
}
</style>
<style id="diag-inc-css">
:root{
--bg-pri:#fff;--bg-sec:#f5f5f4;--bg-ter:#ece9e4;
--bg-info:#e6f1fb;--bg-succ:#eaf3de;--bg-warn:#faeeda;--bg-dang:#fcebeb;
--txt-pri:#1a1a1a;--txt-sec:#4a4a4a;--txt-ter:#888780;
--txt-info:#0c447c;--txt-succ:#27500a;--txt-warn:#633806;--txt-dang:#791f1f;
--bdr-ter:rgba(0,0,0,.12);--bdr-sec:rgba(0,0,0,.22);
--bdr-info:#185fa5;--bdr-succ:#3b6d11;--bdr-warn:#854f0b;--bdr-dang:#a32d2d;
--font:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
--r:8px;
}
html[data-theme="dark"]{
--bg-pri:#0d1117;--bg-sec:#161b22;--bg-ter:#0a0e14;
--bg-info:#0c1d2e;--bg-succ:#0d1f08;--bg-warn:#1e1204;--bg-dang:#190a0a;
--txt-pri:#e6edf3;--txt-sec:#8b949e;--txt-ter:#6e7681;
--txt-info:#58a6ff;--txt-succ:#3fb950;--txt-warn:#e3b341;--txt-dang:#f85149;
--bdr-ter:rgba(255,255,255,.1);--bdr-sec:rgba(255,255,255,.2);
--bdr-info:#1f6feb;--bdr-succ:#2ea043;--bdr-warn:#bb8009;--bdr-dang:#da3633;
}
@media(prefers-color-scheme:dark){
html:not([data-theme="light"]){
--bg-pri:#0d1117;--bg-sec:#161b22;--bg-ter:#0a0e14;
--bg-info:#0c1d2e;--bg-succ:#0d1f08;--bg-warn:#1e1204;--bg-dang:#190a0a;
--txt-pri:#e6edf3;--txt-sec:#8b949e;--txt-ter:#6e7681;
--txt-info:#58a6ff;--txt-succ:#3fb950;--txt-warn:#e3b341;--txt-dang:#f85149;
--bdr-ter:rgba(255,255,255,.1);--bdr-sec:rgba(255,255,255,.2);
--bdr-info:#1f6feb;--bdr-succ:#2ea043;--bdr-warn:#bb8009;--bdr-dang:#da3633;
}
}
*{box-sizing:border-box;margin:0;padding:0}
/* height via view shell */
.view-diagrams{font-family:var(--font);color:var(--txt-pri);background:var(--bg-ter);-webkit-font-smoothing:antialiased}
.view-diagrams .diag-app{display:flex;height:100vh;overflow:hidden}
.view-diagrams .diag-sidebar{width:260px;flex-shrink:0;background:var(--bg-pri);border-right:.5px solid var(--bdr-ter);display:flex;flex-direction:column;overflow:hidden}
.sb-head{padding:14px 12px 10px;border-bottom:.5px solid var(--bdr-ter)}
.sb-head h1{font-size:13px;font-weight:700;line-height:1.35}
.sb-head p{font-size:10px;color:var(--txt-ter);margin-top:4px;line-height:1.45}
.sb-head a{color:var(--txt-info);text-decoration:none}
.sb-head a:hover{text-decoration:underline}
#sb-srch{margin:10px 12px 6px;padding:7px 10px;font-size:12px;border-radius:6px;border:.5px solid var(--bdr-sec);background:var(--bg-sec);color:var(--txt-pri);width:calc(100% - 24px);outline:none}
.sb-list{flex:1;overflow-y:auto;padding:4px 8px 16px}
.sb-sec{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--txt-ter);padding:10px 6px 4px}
.sb-item{display:block;width:100%;text-align:left;padding:6px 10px;border:none;background:none;border-radius:6px;font-size:12px;color:var(--txt-sec);cursor:pointer;margin-bottom:1px}
.sb-item:hover{background:var(--bg-sec);color:var(--txt-pri)}
.sb-item.on{background:var(--bg-info);color:var(--txt-info);font-weight:600}
.view-diagrams .diag-main{flex:1;display:flex;flex-direction:column;min-width:0;overflow:hidden}
.topbar{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--bg-pri);border-bottom:.5px solid var(--bdr-ter);flex-shrink:0;flex-wrap:wrap}
.tb-title{font-size:13px;font-weight:600;flex:1;min-width:120px}
.tb-btn{font-size:11px;padding:5px 10px;border-radius:100px;border:.5px solid var(--bdr-sec);background:transparent;color:var(--txt-sec);cursor:pointer}
.tb-btn:hover,.tb-btn.on{background:var(--bg-info);color:var(--txt-info);border-color:var(--bdr-info)}
.content{flex:1;overflow-y:auto;padding:20px 24px 40px}
.panel{display:none;max-width:1100px;margin:0 auto}
.panel.on{display:block}
.panel h2{font-size:1.35rem;margin-bottom:6px}
.panel .sub{font-size:.9rem;color:var(--txt-sec);line-height:1.55;margin-bottom:14px}
.tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:16px}
.tag{font-size:.72rem;padding:3px 9px;border-radius:100px;background:var(--bg-info);color:var(--txt-info)}
.tag.fail{background:var(--bg-dang);color:var(--txt-dang)}
.tag.flow{background:var(--bg-succ);color:var(--txt-succ)}
.covers{font-size:.85rem;color:var(--txt-sec);line-height:1.6;margin-bottom:16px;padding:10px 14px;background:var(--bg-sec);border-radius:var(--r);border-left:3px solid var(--bdr-info)}
.variant-tabs{display:flex;gap:6px;margin-bottom:12px;flex-wrap:wrap}
.vtab{font-size:12px;font-weight:500;padding:6px 14px;border-radius:100px;border:.5px solid var(--bdr-sec);background:var(--bg-pri);color:var(--txt-sec);cursor:pointer}
.vtab.on{background:var(--bg-dang);color:var(--txt-dang);border-color:var(--bdr-dang)}
.vtab.fix.on{background:var(--bg-succ);color:var(--txt-succ);border-color:var(--bdr-succ)}
.diag-wrap{background:var(--bg-pri);border:1px solid var(--bdr-ter);border-radius:12px;overflow:hidden;margin-bottom:16px}
.diag-toolbar{display:flex;align-items:center;gap:6px;padding:8px 12px;background:var(--bg-sec);border-bottom:.5px solid var(--bdr-ter);flex-wrap:wrap}
.diag-toolbar span{font-size:11px;color:var(--txt-ter);margin-right:auto}
.zbtn{font-size:11px;padding:4px 10px;border-radius:6px;border:.5px solid var(--bdr-sec);background:var(--bg-pri);color:var(--txt-sec);cursor:pointer;min-width:32px}
.zbtn:hover{color:var(--txt-info);border-color:var(--bdr-info)}
.diag-viewport{overflow:auto;min-height:420px;max-height:72vh;padding:32px 24px;cursor:grab;touch-action:none;background:var(--bg-pri)}
.diag-viewport.dragging{cursor:grabbing;user-select:none}
.diag-inner{transform-origin:0 0;transition:transform .12s ease;display:inline-block;min-width:100%}
.diag-inner svg{max-width:none!important;height:auto!important}
.hint{font-size:11px;color:var(--txt-ter);margin-bottom:20px}
.hint kbd{font-size:10px;padding:2px 5px;border-radius:4px;border:.5px solid var(--bdr-sec);background:var(--bg-sec)}
.nav-row{display:flex;justify-content:space-between;gap:12px;margin-top:8px}
.nav-row button{font-size:12px;padding:8px 14px;border-radius:8px;border:.5px solid var(--bdr-sec);background:var(--bg-pri);color:var(--txt-sec);cursor:pointer}
.nav-row button:hover{border-color:var(--bdr-info);color:var(--txt-info)}
.sb-toggle{display:none;position:fixed;top:12px;left:12px;z-index:200;background:var(--bg-pri);border:.5px solid var(--bdr-sec);border-radius:8px;padding:8px 11px;cursor:pointer;font-size:16px}
.sb-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:90}
@media(max-width:768px){
.view-diagrams .diag-app{display:block;height:auto;overflow:visible}
.view-diagrams .diag-main{overflow:visible}
.view-diagrams .diag-sidebar{position:fixed;top:0;left:0;height:100vh;z-index:100;transform:translateX(-100%);transition:transform .22s}
.sidebar.open{transform:translateX(0)}
.sb-toggle{display:block}
.sb-overlay.open{display:block}
.topbar{padding-left:52px}
.content{padding:16px}
.diag-viewport{min-height:320px;max-height:none}
}
.diag-wrap:fullscreen{background:var(--bg-pri);border-radius:0;display:flex;flex-direction:column}
.diag-wrap:fullscreen .diag-viewport{flex:1;max-height:none}
</style>
</head>
<body>
<div class="app">
<aside class="sidebar">
<div style="font-weight:700;font-size:.9rem;margin-bottom:4px">Quick-fire</div>
<div class="view-tabs">
<button class="vtab on" type="button" data-view="patterns">Patterns</button>
<button class="vtab" type="button" data-view="diagrams">Diagrams</button>
</div>
<div id="sb-patterns-tools">
<div style="font-size:.75rem;color:var(--muted);margin-bottom:12px">Browse by topic</div>
<div id="sb-nav"></div>
</div>
<div class="links">
<a href="interview-quick-fire.md">Markdown</a>
<a href="index.html">Index</a>
</div>
</aside>
<div class="content-area">
<div id="view-patterns" class="view-shell view-active">
<main class="main">
<h1>Interview quick-fire</h1>
<p class="hero-sub">Problem → staff-level answer</p>
<div class="lead"><p>When the interviewer pivots mid-design: <em>"How would you handle X?"</em> — answer with <strong>pattern → trade-off → anchor</strong>, then stop unless they want depth.</p><div class="hero-links"><a href="system_design_cheatsheet_v14.html">Full cheatsheet</a><a href="github/v15/index.html">40 system cards</a><a href="interview-quick-fire.html#diagrams">Diagrams</a></div></div>
<div class="legend">
<div class="leg critical">🔴 Critical<small>Outage / cascade</small></div>
<div class="leg high">🟠 High<small>Resilience stress</small></div>
<div class="leg important">🟣 Important<small>Correctness / money</small></div>
<div class="leg pattern">🟢 Pattern<small>Standard flows</small></div>
<div class="leg prep">🔵 Prep<small>Framework & drill</small></div>
</div>
<div class="toolbar">
<input type="search" id="q" placeholder="Search patterns…" autocomplete="off">
<button class="fchip critical" data-f="critical" type="button">🔴 Critical</button>
<button class="fchip high" data-f="high" type="button">🟠 High</button>
<button class="fchip important" data-f="important" type="button">🟣 Important</button>
<button class="fchip pattern" data-f="pattern" type="button">🟢 Pattern</button>
<button class="fchip prep on" data-f="prep" type="button">🔵 Prep</button>
<button class="fchip on" data-f="all" type="button">All</button>
<button class="tb" id="theme" type="button">◐ Theme</button>
<button class="tb" id="expand" type="button">Expand all</button>
</div>
<div id="root"></div>
</main>
</div>
<div id="view-diagrams" class="view-shell view-diagrams">
<button class="sb-toggle" id="diag-sb-tog" aria-label="Menu">☰</button>
<div class="sb-overlay" id="diag-sb-ov"></div>
<div class="diag-app">
<aside class="sidebar" id="diag-sidebar">
<div class="sb-head">
<h1>Diagram archetypes</h1>
<p>17 archetypes · fully offline · <span>17 archetypes · zoom · fullscreen</span></p>
</div>
<input type="search" id="diag-sb-srch" placeholder="Filter diagrams…" autocomplete="off">
<div class="sb-list" id="diag-sb-list"></div>
</aside>
<div class="diag-main">
<div class="topbar">
<span class="tb-title" id="diag-tb-title">Select a diagram</span>
<button class="tb-btn" id="diag-btn-theme" title="Toggle theme">◐ Theme</button>
<button class="tb-btn" id="diag-btn-fit" title="Fit to view">Fit</button>
</div>
<div class="content" id="diag-panels"></div>
</div>
</div>
</div>
</div>
</div>
<script src="vendor/mermaid.min.js"></script>
<script id="diag-inc-js">
const DIAGRAMS = [
{
id: 'cache-aside', title: 'Cache-aside', cat: 'flows', kind: 'flow',
covers: 'Reduce DB read load, stale cache after update, CDN as edge cache layer.',
tags: ['reads', 'caching'],
mermaid: `flowchart LR
C[Client] --> A[App]
A --> R{Redis hit?}
R -->|yes| A
R -->|miss| D[(Primary DB)]
D --> A
A -->|populate| R
W[Write] --> D
W -->|invalidate| R`
},
{
id: 'thundering-herd', title: 'Thundering herd', cat: 'failures', kind: 'failure',
covers: 'Thundering herd, cache stampede — synchronized TTL expiry vs single-flight fix.',
tags: ['failure', 'caching'],
variants: [
{ id: 'bad', label: 'Without fix', cls: '', mermaid: `sequenceDiagram
participant C1 as Clients x1000
participant Redis
participant DB as Primary DB
Note over Redis: TTL expires together
C1->>Redis: GET all miss
C1->>DB: SELECT x1000
Note over DB: Pool exhausted` },
{ id: 'fix', label: 'Single-flight fix', cls: 'fix', mermaid: `sequenceDiagram
participant C1 as Client A
participant C2 as Clients B..N
participant App
participant Redis
participant DB
C1->>App: GET key
C2->>App: GET key
App->>App: lock key single-flight
App->>DB: one SELECT
App->>Redis: SET
App-->>C1: 200 OK
App-->>C2: 200 same payload` }
]
},
{
id: 'retry-storm', title: 'Retry storm', cat: 'failures', kind: 'failure',
covers: 'Retry storm, metastable failure, cascading failure, circuit breaker.',
tags: ['failure', 'resilience'],
mermaid: `flowchart TD
C[Clients timeout] -->|retry x3| API[API at 80% CPU]
API -->|slower| C
API --> CB{Circuit breaker}
CB -->|open| F[Fail fast 503]
CB -->|half-open| P[Probe 1 req/s]
F --> Q[Queue async reconcile]`
},
{
id: 'hot-key', title: 'Hot key', cat: 'failures', kind: 'failure',
covers: 'Hot partition, viral URL, segmented counters, celebrity fan-out threshold.',
tags: ['failure', 'caching'],
mermaid: `flowchart TD
subgraph bad[One Redis key overload]
K[viral:url:abc] --> O[Overload]
end
subgraph fix[Mitigations]
L[Local LRU per app] --> K2[Logical shards url:abc:1..8]
K2 --> CDN[CDN edge cache]
end`
},
{
id: 'split-brain', title: 'Split brain', cat: 'failures', kind: 'failure',
covers: 'Network partition, dual primary, fencing tokens, quorum writes.',
tags: ['failure', 'consistency'],
mermaid: `flowchart TD
P[Primary AZ-a] ---X--- R[Replica AZ-b]
P -->|both think primary| W1[Writes set A]
R --> W2[Writes set B]
W1 --> D[Divergent data]
W2 --> D
Q[Quorum / fencing token] -.->|fix| P`
},
{
id: 'poison-message', title: 'Poison message', cat: 'failures', kind: 'failure',
covers: 'Poison pill, head-of-line blocking — split fast/slow queues.',
tags: ['failure', 'messaging'],
mermaid: `flowchart LR
P[Producer] --> K[Kafka topic]
K --> W[Worker]
W -->|crash loop| W
W -->|attempt 3| DLQ[Dead letter queue]
DLQ --> Ops[Alert + manual replay]`
},
{
id: 'n1-batch', title: 'N+1 vs batch', cat: 'failures', kind: 'failure',
covers: 'N+1 queries, DataLoader pattern, batch WHERE id IN.',
tags: ['failure', 'reads'],
mermaid: `flowchart TD
subgraph n1[N+1 bad]
A1[Load 500 posts] --> Q1[500 profile queries]
end
subgraph batch[DataLoader good]
A2[Load 500 posts] --> Q2[1 query WHERE id IN]
end`
},
{
id: 'connection-pool', title: 'Connection pool exhaustion', cat: 'failures', kind: 'failure',
covers: 'Pool saturation, slow transactions, retry storm feedback loop.',
tags: ['failure', 'database'],
mermaid: `flowchart TD
Apps[100 app instances] --> Pool[PgBouncer max 200]
Pool -->|held by slow TX| Block[New requests wait]
Block -->|30s timeout| Storm[Retry storm]
T[Query timeout + right-size pool] -.-> Pool`
},
{
id: 'replica-lag', title: 'Replica lag', cat: 'failures', kind: 'failure',
covers: 'Stale read, read-your-writes, route to primary after write.',
tags: ['failure', 'consistency'],
mermaid: `sequenceDiagram
participant U as User
participant App
participant P as Primary
participant R as Replica lag 30s
U->>App: POST comment
App->>P: INSERT
U->>App: GET feed
App->>R: SELECT misses new comment
Note over App: Fix RYW to Primary 5s`
},
{
id: 'dual-write', title: 'Dual-write vs outbox', cat: 'flows', kind: 'flow',
covers: 'Dual-write drift, Elasticsearch index, webhook outbox, CDC.',
tags: ['writes', 'consistency'],
mermaid: `flowchart TD
subgraph bad[Dual-write risky]
App1[App] --> DB[(DB)]
App1 --> ES[Elasticsearch]
end
subgraph good[Outbox + CDC]
App2[App] --> DB2[(DB + outbox row)]
DB2 --> CDC[Debezium relay]
CDC --> ES2[Elasticsearch]
end`
},
{
id: 'fan-out', title: 'Fan-out hybrid', cat: 'flows', kind: 'flow',
covers: 'Push vs pull feeds, celebrity threshold, push notification stagger.',
tags: ['fan-out', 'writes'],
mermaid: `flowchart TD
Post[New post] --> H{followers count}
H -->|under 10K| Push[Push to follower feeds via Kafka]
H -->|celebrity| Pull[Store post only pull on read]
Push --> Redis[Redis timelines]
Pull --> Store[(Post store)]`
},
{
id: 'saga', title: 'Saga', cat: 'flows', kind: 'flow',
covers: 'Cross-service transactions, compensating transactions, payment + inventory.',
tags: ['consistency', 'payments'],
mermaid: `sequenceDiagram
participant O as Orchestrator
participant Pay as Payment
participant Inv as Inventory
O->>Pay: charge
Pay-->>O: OK
O->>Inv: reserve
Inv-->>O: fail
O->>Pay: compensate refund`
},
{
id: 'idempotency', title: 'Idempotency', cat: 'flows', kind: 'flow',
covers: 'Idempotency-Key header, safe retries, payment deduplication.',
tags: ['writes', 'payments'],
mermaid: `sequenceDiagram
participant C as Client
participant API
participant Store as Idempotency store
C->>API: POST key=abc
API->>Store: insert abc
API-->>C: 201 charged
C->>API: POST key=abc retry
API->>Store: found abc
API-->>C: 201 same response`
},
{
id: 'seat-hold', title: 'Seat hold 2-phase', cat: 'flows', kind: 'flow',
covers: 'Double booking, flash sale, Redis soft hold + PG hard commit.',
tags: ['contention', 'payments'],
mermaid: `sequenceDiagram
participant U as User
participant API
participant Redis
participant PG as Postgres
U->>API: book seat
API->>Redis: SETNX seat TTL 10m
API-->>U: held
U->>API: pay
API->>PG: BEGIN SELECT FOR UPDATE commit
API->>Redis: DEL hold`
},
{
id: 'straggler', title: 'Scatter-gather straggler', cat: 'failures', kind: 'failure',
covers: 'Slow shard, hedged reads, partial results, timeout per shard.',
tags: ['failure', 'reads'],
mermaid: `flowchart TD
Q[Query coordinator] --> S1[Shard 1 20ms]
Q --> S2[Shard 2 20ms]
Q --> S3[Shard 3 3000ms straggler]
Q -->|timeout 500ms| P[Return partial 19/20 shards]`
},
{
id: 'token-bucket', title: 'Token bucket rate limit', cat: 'flows', kind: 'flow',
covers: 'Rate limiting, DDoS edge control, burst allowance vs steady rate.',
tags: ['security'],
mermaid: `flowchart LR
R[Refill R tokens/sec] --> B[Bucket max B burst]
Req[Request] -->|cost 1 token| B
B -->|tokens OK| Allow[Forward to API]
B -->|empty| Deny[429 Retry-After]`
},
{
id: 'websocket-scale', title: 'WebSocket at scale', cat: 'flows', kind: 'flow',
covers: 'Connection registry, Redis pub/sub bridge, sticky sessions vs shared bus.',
tags: ['real-time'],
mermaid: `flowchart LR
C1[User A] --> WS1[WS server 1]
C2[User B] --> WS2[WS server 2]
WS1 -->|publish| PS[Redis pub/sub]
PS -->|subscribe| WS2
WS1 --> Reg[(user_id to server_id)]`
}
];
let currentId = null;
let zoom = 1;
let panX = 0, panY = 0;
let mermaidReady = false;
function isDark() {
const t = document.documentElement.dataset.theme;
if (t === 'dark') return true;
if (t === 'light') return false;
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
function initMermaid() {
mermaid.initialize({
startOnLoad: false,
theme: isDark() ? 'dark' : 'default',
securityLevel: 'loose',
flowchart: { useMaxWidth: false, htmlLabels: true, curve: 'basis' },
sequence: { useMaxWidth: false, actorMargin: 90, messageMargin: 45, mirrorActors: true, wrap: true },
themeVariables: { fontSize: '17px', fontFamily: '-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif' }
});
mermaidReady = true;
}
function esc(s) { return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }
function buildSidebar() {
const list = document.getElementById('diag-sb-list');
const failures = DIAGRAMS.filter(d => d.cat === 'failures');
const flows = DIAGRAMS.filter(d => d.cat === 'flows');
let html = '<div class="sb-sec">Failure modes</div>';
failures.forEach(d => { html += `<button class="sb-item" data-id="${d.id}" type="button">${esc(d.title)}</button>`; });
html += '<div class="sb-sec">Core flows</div>';
flows.forEach(d => { html += `<button class="sb-item" data-id="${d.id}" type="button">${esc(d.title)}</button>`; });
list.innerHTML = html;
list.querySelectorAll('.sb-item').forEach(btn => {
btn.addEventListener('click', () => { show(btn.dataset.id); closeSidebar(); });
});
}
function buildPanels() {
const root = document.getElementById('diag-panels');
root.innerHTML = DIAGRAMS.map(d => {
const tagCls = d.kind === 'failure' ? 'fail' : 'flow';
let tabs = '';
let bodies = '';
if (d.variants) {
tabs = '<div class="variant-tabs">' + d.variants.map((v, i) =>
`<button class="vtab ${v.cls}${i === 0 ? ' on' : ''}" data-panel="${d.id}" data-var="${v.id}" type="button">${esc(v.label)}</button>`
).join('') + '</div>';
bodies = d.variants.map((v, i) =>
`<div class="variant-body" data-panel="${d.id}" data-var="${v.id}" style="${i ? 'display:none' : ''}">${diagBlock(d.id, v.id, v.mermaid)}</div>`
).join('');
} else {
bodies = diagBlock(d.id, 'main', d.mermaid);
}
return `<section class="panel" id="panel-${d.id}" data-title="${esc(d.title)}">
<h2>${esc(d.title)}</h2>
<p class="sub">Redraw this on a whiteboard in 60 seconds — label boxes for the system you're designing.</p>
<div class="tags">${d.tags.map(t => `<span class="tag ${tagCls}">${esc(t)}</span>`).join('')}</div>
<div class="covers"><strong>Covers:</strong> ${esc(d.covers)}</div>
${tabs}${bodies}
<p class="hint">Scroll to zoom · drag to pan · <kbd>+</kbd>/<kbd>−</kbd> zoom · <kbd>←</kbd><kbd>→</kbd> prev/next · double-click diagram to reset</p>
<div class="nav-row">
<button type="button" data-nav="prev">← Previous</button>
<button type="button" data-nav="next">Next →</button>
</div>
</section>`;
}).join('');
root.querySelectorAll('.vtab').forEach(tab => {
tab.addEventListener('click', () => {
const pid = tab.dataset.panel, vid = tab.dataset.var;
root.querySelectorAll(`.vtab[data-panel="${pid}"]`).forEach(t => t.classList.toggle('on', t === tab));
root.querySelectorAll(`.variant-body[data-panel="${pid}"]`).forEach(b => {
b.style.display = b.dataset.var === vid ? '' : 'none';
});
resetView(pid, vid);
});
});
root.querySelectorAll('[data-nav]').forEach(btn => {
btn.addEventListener('click', () => navigate(btn.dataset.nav === 'next' ? 1 : -1));
});
setupDiagInteractions();
}
function diagBlock(panelId, varId, src) {
const uid = `${panelId}-${varId}`;
return `<div class="diag-wrap" id="wrap-${uid}">
<div class="diag-toolbar">
<span>Drag to pan · use +/− to zoom</span>
<button class="zbtn" type="button" data-zoom="-">−</button>
<button class="zbtn" type="button" data-zoom="0">100%</button>
<button class="zbtn" type="button" data-zoom="+">+</button>
<button class="zbtn" type="button" data-fs="${uid}">⛶ Fullscreen</button>
</div>
<div class="diag-viewport" data-vp="${uid}">
<div class="diag-inner" data-inner="${uid}">
<pre class="mermaid" id="mm-${uid}">${src}</pre>
</div>
</div>
</div>`;
}
async function renderAllMermaid() {
const nodes = document.querySelectorAll('.mermaid');
for (const el of nodes) {
const id = el.id.replace('mm-', 'svg-');
try {
const { svg } = await mermaid.render(id, el.textContent.trim());
el.outerHTML = svg;
} catch (e) {
el.outerHTML = `<p style="color:var(--txt-dang);padding:12px">Render error: ${esc(String(e.message || e))}</p>`;
}
}
}
function setupDiagInteractions() {
document.querySelectorAll('.zbtn[data-zoom]').forEach(btn => {
btn.addEventListener('click', () => {
const d = btn.dataset.zoom;
if (d === '+') setZoom(zoom + 0.15);
else if (d === '-') setZoom(zoom - 0.15);
else setZoom(1, true);
});
});
document.querySelectorAll('.zbtn[data-fs]').forEach(btn => {
btn.addEventListener('click', () => {
const wrap = document.getElementById('wrap-' + btn.dataset.fs);
if (wrap.requestFullscreen) wrap.requestFullscreen();
else wrap.webkitRequestFullscreen?.();
});
});
document.querySelectorAll('.diag-viewport').forEach(vp => {
let dragging = false, sx, sy, spx, spy;
vp.addEventListener('wheel', e => {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
setZoom(zoom + (e.deltaY < 0 ? 0.1 : -0.1));
}
}, { passive: false });
vp.addEventListener('mousedown', e => {
if (e.button !== 0) return;
dragging = true;
sx = e.clientX; sy = e.clientY;
spx = panX; spy = panY;
vp.classList.add('dragging');
});
window.addEventListener('mousemove', e => {
if (!dragging) return;
panX = spx + (e.clientX - sx);
panY = spy + (e.clientY - sy);
applyTransform();
});
window.addEventListener('mouseup', () => {
dragging = false;
vp.classList.remove('dragging');
});
vp.addEventListener('dblclick', () => resetViewForVp(vp));
});
}
function applyTransform() {
document.querySelectorAll('.diag-inner').forEach(el => {
el.style.transform = `translate(${panX}px, ${panY}px) scale(${zoom})`;
});
}
function setZoom(z, resetPan) {
zoom = Math.min(2.5, Math.max(0.35, z));
if (resetPan) { panX = 0; panY = 0; }
applyTransform();
}
function resetView(panelId, varId) {
zoom = 1; panX = 0; panY = 0;
applyTransform();
}
function resetViewForVp(vp) {
zoom = 1; panX = 0; panY = 0;
applyTransform();
}
function show(id) {
if (!DIAGRAMS.find(d => d.id === id)) return;
currentId = id;
document.querySelectorAll('.panel').forEach(p => p.classList.toggle('on', p.id === 'panel-' + id));
document.querySelectorAll('.sb-item').forEach(b => b.classList.toggle('on', b.dataset.id === id));
const d = DIAGRAMS.find(x => x.id === id);
document.getElementById('diag-tb-title').textContent = d.title;
location.hash = id;
resetView(id);
document.querySelector('.panel.on')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function navigate(dir) {
const i = DIAGRAMS.findIndex(d => d.id === currentId);
const j = (i + dir + DIAGRAMS.length) % DIAGRAMS.length;
show(DIAGRAMS[j].id);
}
function filterSidebar(q) {
const qq = q.toLowerCase().trim();
document.querySelectorAll('.sb-item').forEach(btn => {
const d = DIAGRAMS.find(x => x.id === btn.dataset.id);
const hay = (d.title + ' ' + d.covers + ' ' + d.tags.join(' ')).toLowerCase();
btn.style.display = !qq || hay.includes(qq) ? '' : 'none';
});
}
function closeSidebar() {
document.getElementById('diag-sidebar').classList.remove('open');
document.getElementById('diag-sb-ov').classList.remove('open');
}
function toggleSidebar() {
document.getElementById('diag-sidebar').classList.toggle('open');
document.getElementById('diag-sb-ov').classList.toggle('open');
}
document.getElementById('diag-sb-tog').onclick = toggleSidebar;
document.getElementById('diag-sb-ov').onclick = closeSidebar;
document.getElementById('diag-sb-srch').oninput = e => filterSidebar(e.target.value);
document.getElementById('diag-btn-fit').onclick = () => setZoom(1, true);
document.getElementById('diag-btn-theme').onclick = () => {
const dark = isDark();
document.documentElement.dataset.theme = dark ? 'light' : 'dark';
localStorage.setItem('qf-color-theme', document.documentElement.dataset.theme);
location.reload();
};
document.addEventListener('keydown', e => {
if (e.target.matches('input')) return;
if (e.key === 'ArrowRight') navigate(1);
if (e.key === 'ArrowLeft') navigate(-1);
if (e.key === '+' || e.key === '=') setZoom(zoom + 0.15);
if (e.key === '-') setZoom(zoom - 0.15);
if (e.key === '0') setZoom(1, true);
});
window.bootDiagrams = async function(hashId) {
if (window._diagramsBooted) {
if (hashId && DIAGRAMS.find(d => d.id === hashId)) show(hashId);
return;
}
initMermaid();
buildSidebar();
buildPanels();
await renderAllMermaid();
window._diagramsBooted = true;
const hash = hashId || location.hash.replace('#', '');
show(DIAGRAMS.find(d => d.id === hash)?.id || DIAGRAMS[0].id);
};
</script>
<script>
const SEV = {"critical": {"emoji": "🔴", "label": "Critical", "alert": "CAUTION", "hint": "Outage / data-loss risk — probe failure modes first", "css": "sev-critical"}, "high": {"emoji": "🟠", "label": "High", "alert": "WARNING", "hint": "Resilience under stress — name degraded mode + recovery", "css": "sev-high"}, "important": {"emoji": "🟣", "label": "Important", "alert": "IMPORTANT", "hint": "Correctness / invariants — strong consistency territory", "css": "sev-important"}, "pattern": {"emoji": "🟢", "label": "Pattern", "alert": "TIP", "hint": "Core design pattern — pattern + trade-off + anchor", "css": "sev-pattern"}, "prep": {"emoji": "🔵", "label": "Prep", "alert": "NOTE", "hint": "Interview framework — how to answer and go deeper", "css": "sev-prep"}};
const DATA = [{"title": "Classic failure modes & distributed pitfalls", "slug": "classic-failure-modes-distributed-pitfalls", "severity": "critical", "patterns": [{"title": "Thundering herd", "slug": "thundering-herd", "problem": "What happens when your cache TTL expires and thousands of clients hit the database at once?", "weak": "Add caching — TTL expires, everyone hits the DB.", "staff": "Many clients miss cache (or TTL expires) at the same instant and all hit the origin/DB together. Fix with **request coalescing / single-flight** (one goroutine repopulates; others wait on the same future), **staggered TTL jitter** (±10–20% on expiry), **probabilistic early refresh** (background recompute before hard expiry), and **cache warming** after deploys. Add a **local in-process LRU** on app servers so the hottest keys never trigger a network miss storm.", "staff_plus": "Single-flight adds tail latency for waiters on cold miss. Jitter makes freshness less predictable per key. Local cache introduces per-node staleness — fine for redirects, wrong for inventory counts. Example: Redis restart during peak → 100% miss → Postgres connection pool exhausted in seconds. Netflix-style: mutex per key + early async refresh. Name metric + revisit trigger when they push depth.", "trade": "Single-flight adds tail latency for waiters on cold miss. Jitter makes freshness less predictable per key. Local cache introduces per-node staleness — fine for redirects, wrong for inventory counts.", "example": "*Redis restart during peak → 100% miss → Postgres connection pool exhausted in seconds. Netflix-style: mutex per key + early async refresh.*", "visual": "[Thundering herd](interview-quick-fire.html#thundering-herd)", "java_blocks": [], "severity": "critical", "problem_html": "What happens when your cache TTL expires and thousands of clients hit the database at once?", "weak_html": "Add caching — TTL expires, everyone hits the DB.", "staff_html": "Many clients miss cache (or TTL expires) at the same instant and all hit the origin/DB together. Fix with <strong>request coalescing / single-flight</strong> (one goroutine repopulates; others wait on the same future), <strong>staggered TTL jitter</strong> (±10–20% on expiry), <strong>probabilistic early refresh</strong> (background recompute before hard expiry), and <strong>cache warming</strong> after deploys. Add a <strong>local in-process LRU</strong> on app servers so the hottest keys never trigger a network miss storm.", "staff_plus_html": "Single-flight adds tail latency for waiters on cold miss. Jitter makes freshness less predictable per key. Local cache introduces per-node staleness — fine for redirects, wrong for inventory counts. Example: Redis restart during peak → 100% miss → Postgres connection pool exhausted in seconds. Netflix-style: mutex per key + early async refresh. Name metric + revisit trigger when they push depth.", "trade_html": "Single-flight adds tail latency for waiters on cold miss. Jitter makes freshness less predictable per key. Local cache introduces per-node staleness — fine for redirects, wrong for inventory counts.", "example_html": "<em>Redis restart during peak → 100% miss → Postgres connection pool exhausted in seconds. Netflix-style: mutex per key + early async refresh.</em>", "visual_html": "<a href=\"#thundering-herd\" class=\"diag-link\" data-diag=\"thundering-herd\">Thundering herd</a>", "java_html": "", "java": ""}, {"title": "Cache stampede (dogpile)", "slug": "cache-stampede-dogpile", "problem": "An expensive cached computation expires — how do you stop every request from re-running it simultaneously?", "weak": "Cache the expensive query with a fixed TTL.", "staff": "Same family as thundering herd but specifically on **expensive recompute** (heavy DB query, ML ranker). Beyond single-flight: **lock with short lease**, **precompute in background** before TTL fires, **two-tier TTL** (soft expire → serve stale while one worker refreshes). For viral keys, **bypass cache logic entirely** — route to a dedicated read path or materialized view.", "staff_plus": "Serving stale during refresh trades UX accuracy for availability — must define max staleness SLA. Background refresh burns CPU on keys nobody reads (wasted work without hit-rate signal). Example: Feed ranker takes 200ms; 10K concurrent misses = 2K parallel rank jobs. Fix: one refresh job per `(user, feed)` key; readers get previous snapshot. Name metric + revisit trigger when they push depth.", "trade": "Serving stale during refresh trades UX accuracy for availability — must define max staleness SLA. Background refresh burns CPU on keys nobody reads (wasted work without hit-rate signal).", "example": "*Feed ranker takes 200ms; 10K concurrent misses = 2K parallel rank jobs. Fix: one refresh job per `(user, feed)` key; readers get previous snapshot.*", "visual": "[Thundering herd](interview-quick-fire.html#thundering-herd) *(add serve-stale branch)*", "java_blocks": [], "severity": "critical", "problem_html": "An expensive cached computation expires — how do you stop every request from re-running it simultaneously?", "weak_html": "Cache the expensive query with a fixed TTL.", "staff_html": "Same family as thundering herd but specifically on <strong>expensive recompute</strong> (heavy DB query, ML ranker). Beyond single-flight: <strong>lock with short lease</strong>, <strong>precompute in background</strong> before TTL fires, <strong>two-tier TTL</strong> (soft expire → serve stale while one worker refreshes). For viral keys, <strong>bypass cache logic entirely</strong> — route to a dedicated read path or materialized view.", "staff_plus_html": "Serving stale during refresh trades UX accuracy for availability — must define max staleness SLA. Background refresh burns CPU on keys nobody reads (wasted work without hit-rate signal). Example: Feed ranker takes 200ms; 10K concurrent misses = 2K parallel rank jobs. Fix: one refresh job per <code>(user, feed)</code> key; readers get previous snapshot. Name metric + revisit trigger when they push depth.", "trade_html": "Serving stale during refresh trades UX accuracy for availability — must define max staleness SLA. Background refresh burns CPU on keys nobody reads (wasted work without hit-rate signal).", "example_html": "<em>Feed ranker takes 200ms; 10K concurrent misses = 2K parallel rank jobs. Fix: one refresh job per <code>(user, feed)</code> key; readers get previous snapshot.</em>", "visual_html": "<a href=\"#thundering-herd\" class=\"diag-link\" data-diag=\"thundering-herd\">Thundering herd</a> <em>(add serve-stale branch)</em>", "java_html": "", "java": ""}, {"title": "Retry storm", "slug": "retry-storm", "problem": "Clients retry on timeout, the service slows down, and retries multiply — how do you break the loop?", "weak": "Retry on any timeout — clients will eventually succeed.", "staff": "Clients or middleware retry aggressively on timeout, **multiplying load on a already-degraded service**. Use **exponential backoff with jitter**, **retry budgets** (max N per request chain), **circuit breakers** that fail fast, and **429 + Retry-After** from the server. Idempotency keys on mutating retries so duplicates are safe.", "staff_plus": "Fewer retries increase user-visible errors during brief blips. Circuit open = hard failures — need half-open probes and alerting. Aggressive backoff slows recovery perception for humans. Example: Payment API at 80% CPU; clients retry 3× → effective load 240%. Breaker opens; queue for async reconciliation instead. Name metric + revisit trigger when they push depth.", "trade": "Fewer retries increase user-visible errors during brief blips. Circuit open = hard failures — need half-open probes and alerting. Aggressive backoff slows recovery perception for humans.", "example": "*Payment API at 80% CPU; clients retry 3× → effective load 240%. Breaker opens; queue for async reconciliation instead.*", "visual": "[Retry storm](interview-quick-fire.html#retry-storm)", "java_blocks": [], "severity": "critical", "problem_html": "Clients retry on timeout, the service slows down, and retries multiply — how do you break the loop?", "weak_html": "Retry on any timeout — clients will eventually succeed.", "staff_html": "Clients or middleware retry aggressively on timeout, <strong>multiplying load on a already-degraded service</strong>. Use <strong>exponential backoff with jitter</strong>, <strong>retry budgets</strong> (max N per request chain), <strong>circuit breakers</strong> that fail fast, and <strong>429 + Retry-After</strong> from the server. Idempotency keys on mutating retries so duplicates are safe.", "staff_plus_html": "Fewer retries increase user-visible errors during brief blips. Circuit open = hard failures — need half-open probes and alerting. Aggressive backoff slows recovery perception for humans. Example: Payment API at 80% CPU; clients retry 3× → effective load 240%. Breaker opens; queue for async reconciliation instead. Name metric + revisit trigger when they push depth.", "trade_html": "Fewer retries increase user-visible errors during brief blips. Circuit open = hard failures — need half-open probes and alerting. Aggressive backoff slows recovery perception for humans.", "example_html": "<em>Payment API at 80% CPU; clients retry 3× → effective load 240%. Breaker opens; queue for async reconciliation instead.</em>", "visual_html": "<a href=\"#retry-storm\" class=\"diag-link\" data-diag=\"retry-storm\">Retry storm</a>", "java_html": "", "java": ""}, {"title": "Metastable failure", "slug": "metastable-failure", "problem": "The system was stable at 70% load but collapses at 80% and cannot recover — what is happening?", "weak": "Wait for autoscale; retries will fix it.", "staff": "System has **two stable states** (healthy vs overloaded) and overload persists even after trigger is gone — retries, autoscale lag, GC piles, connection churn keep it stuck. Fix: **load shedding** early (drop low-priority work), **admission control** at edge, **enforce timeouts** everywhere, **disable retries** on read path under stress. Recovery often needs **manual traffic throttle**, not just \"wait for autoscale.\"", "staff_plus": "Shedding load means deliberately failing some users to save the rest — product/policy decision. Turning off retries hurts success rate metrics during incidents (the right trade). Example: AWS ALB + Lambda cold starts + retry loops → hours of elevated errors after a 2-minute DB blip. Name metric + revisit trigger when they push depth.", "trade": "Shedding load means deliberately failing some users to save the rest — product/policy decision. Turning off retries hurts success rate metrics during incidents (the right trade).", "example": "*AWS ALB + Lambda cold starts + retry loops → hours of elevated errors after a 2-minute DB blip.*", "visual": "[Retry storm](interview-quick-fire.html#retry-storm) *(stuck in overload loop)*", "java_blocks": [], "severity": "critical", "problem_html": "The system was stable at 70% load but collapses at 80% and cannot recover — what is happening?", "weak_html": "Wait for autoscale; retries will fix it.", "staff_html": "System has <strong>two stable states</strong> (healthy vs overloaded) and overload persists even after trigger is gone — retries, autoscale lag, GC piles, connection churn keep it stuck. Fix: <strong>load shedding</strong> early (drop low-priority work), <strong>admission control</strong> at edge, <strong>enforce timeouts</strong> everywhere, <strong>disable retries</strong> on read path under stress. Recovery often needs <strong>manual traffic throttle</strong>, not just "wait for autoscale."", "staff_plus_html": "Shedding load means deliberately failing some users to save the rest — product/policy decision. Turning off retries hurts success rate metrics during incidents (the right trade). Example: AWS ALB + Lambda cold starts + retry loops → hours of elevated errors after a 2-minute DB blip. Name metric + revisit trigger when they push depth.", "trade_html": "Shedding load means deliberately failing some users to save the rest — product/policy decision. Turning off retries hurts success rate metrics during incidents (the right trade).", "example_html": "<em>AWS ALB + Lambda cold starts + retry loops → hours of elevated errors after a 2-minute DB blip.</em>", "visual_html": "<a href=\"#retry-storm\" class=\"diag-link\" data-diag=\"retry-storm\">Retry storm</a> <em>(stuck in overload loop)</em>", "java_html": "", "java": ""}, {"title": "Hot partition / hot key", "slug": "hot-partition-hot-key", "problem": "One Redis key or DB partition gets 100× normal traffic — how do you handle it?", "weak": "Scale Redis vertically when one key gets hot.", "staff": "One shard or Redis key gets disproportionate traffic (celebrity tweet, viral URL, global counter). **Detect** via per-key QPS metrics. **Mitigate:** sub-key sharding (logical fan-out), **local cache** on app tier, **read replicas** dedicated to hot range, **async aggregation** (writes to buffer, periodic flush). For counters: **segmented counters** (shard add locally, sum on read).", "staff_plus": "Segmented counters make real-time exact counts harder. Local cache breaks global consistency. Splitting one hot key across shards complicates read path. Example: Justin Bieber tweet fan-out — Twitter switched to pull model for >10M follower accounts. Name metric + revisit trigger when they push depth.", "trade": "Segmented counters make real-time exact counts harder. Local cache breaks global consistency. Splitting one hot key across shards complicates read path.", "example": "*Justin Bieber tweet fan-out — Twitter switched to pull model for >10M follower accounts.*", "visual": "[Hot key](interview-quick-fire.html#hot-key) · [Fan-out hybrid](interview-quick-fire.html#fan-out)", "java_blocks": [], "severity": "critical", "problem_html": "One Redis key or DB partition gets 100× normal traffic — how do you handle it?", "weak_html": "Scale Redis vertically when one key gets hot.", "staff_html": "One shard or Redis key gets disproportionate traffic (celebrity tweet, viral URL, global counter). <strong>Detect</strong> via per-key QPS metrics. <strong>Mitigate:</strong> sub-key sharding (logical fan-out), <strong>local cache</strong> on app tier, <strong>read replicas</strong> dedicated to hot range, <strong>async aggregation</strong> (writes to buffer, periodic flush). For counters: <strong>segmented counters</strong> (shard add locally, sum on read).", "staff_plus_html": "Segmented counters make real-time exact counts harder. Local cache breaks global consistency. Splitting one hot key across shards complicates read path. Example: Justin Bieber tweet fan-out — Twitter switched to pull model for >10M follower accounts. Name metric + revisit trigger when they push depth.", "trade_html": "Segmented counters make real-time exact counts harder. Local cache breaks global consistency. Splitting one hot key across shards complicates read path.", "example_html": "<em>Justin Bieber tweet fan-out — Twitter switched to pull model for >10M follower accounts.</em>", "visual_html": "<a href=\"#hot-key\" class=\"diag-link\" data-diag=\"hot-key\">Hot key</a> · <a href=\"#fan-out\" class=\"diag-link\" data-diag=\"fan-out\">Fan-out hybrid</a>", "java_html": "", "java": ""}, {"title": "Split brain", "slug": "split-brain", "problem": "Your DB primary fails over but the old primary still accepts writes — how do you prevent split brain?", "weak": "Promote replica on primary failure — keep serving writes.", "staff": "Network partition causes **two nodes to believe they're primary** — risk of divergent writes. Prefer **quorum writes** (Raft/Paxos), **fencing tokens** (monotonic epoch; stale primary can't commit), **STONITH** in infra layers. For caches/locks: **Redlock is controversial** — say you'd use a consensus-backed lock or DB lease with TTL.", "staff_plus": "Quorum adds latency and needs odd number of AZs. Fencing requires plumbing through all storage layers. Availability during partition: CP systems reject writes (unavailable), AP systems risk inconsistency. Example: Redis primary + async replica both promoted after partition → duplicate short codes. Fix: etcd lease + single writer. Name metric + revisit trigger when they push depth.", "trade": "Quorum adds latency and needs odd number of AZs. Fencing requires plumbing through all storage layers. Availability during partition: CP systems reject writes (unavailable), AP systems risk inconsistency.", "example": "*Redis primary + async replica both promoted after partition → duplicate short codes. Fix: etcd lease + single writer.*", "visual": "[Split brain](interview-quick-fire.html#split-brain)", "java_blocks": [], "severity": "critical", "problem_html": "Your DB primary fails over but the old primary still accepts writes — how do you prevent split brain?", "weak_html": "Promote replica on primary failure — keep serving writes.", "staff_html": "Network partition causes <strong>two nodes to believe they're primary</strong> — risk of divergent writes. Prefer <strong>quorum writes</strong> (Raft/Paxos), <strong>fencing tokens</strong> (monotonic epoch; stale primary can't commit), <strong>STONITH</strong> in infra layers. For caches/locks: <strong>Redlock is controversial</strong> — say you'd use a consensus-backed lock or DB lease with TTL.", "staff_plus_html": "Quorum adds latency and needs odd number of AZs. Fencing requires plumbing through all storage layers. Availability during partition: CP systems reject writes (unavailable), AP systems risk inconsistency. Example: Redis primary + async replica both promoted after partition → duplicate short codes. Fix: etcd lease + single writer. Name metric + revisit trigger when they push depth.", "trade_html": "Quorum adds latency and needs odd number of AZs. Fencing requires plumbing through all storage layers. Availability during partition: CP systems reject writes (unavailable), AP systems risk inconsistency.", "example_html": "<em>Redis primary + async replica both promoted after partition → duplicate short codes. Fix: etcd lease + single writer.</em>", "visual_html": "<a href=\"#split-brain\" class=\"diag-link\" data-diag=\"split-brain\">Split brain</a>", "java_html": "", "java": ""}, {"title": "Poison message", "slug": "poison-message", "problem": "One bad queue message crashes every consumer — how do you isolate it without stopping the pipeline?", "weak": "Restart the consumer until the message processes.", "staff": "One bad message crashes consumer in a loop (malformed payload, unexpected schema). **DLQ** after N attempts, **schema validation** at ingest, **poison pill quarantine** with alert. Replay DLQ only after fix deployed. Separate **canary consumer** on new schema versions.", "staff_plus": "DLQ delays processing for bad messages (operational toil). Strict validation rejects valid edge cases if schema too tight. Example: Kafka consumer OOM on 12MB JSON → partition stuck. Move to DLQ; fix deserializer; replay with size cap. Name metric + revisit trigger when they push depth.", "trade": "DLQ delays processing for bad messages (operational toil). Strict validation rejects valid edge cases if schema too tight.", "example": "*Kafka consumer OOM on 12MB JSON → partition stuck. Move to DLQ; fix deserializer; replay with size cap.*", "visual": "[Poison message](interview-quick-fire.html#poison-message)", "java_blocks": [], "severity": "critical", "problem_html": "One bad queue message crashes every consumer — how do you isolate it without stopping the pipeline?", "weak_html": "Restart the consumer until the message processes.", "staff_html": "One bad message crashes consumer in a loop (malformed payload, unexpected schema). <strong>DLQ</strong> after N attempts, <strong>schema validation</strong> at ingest, <strong>poison pill quarantine</strong> with alert. Replay DLQ only after fix deployed. Separate <strong>canary consumer</strong> on new schema versions.", "staff_plus_html": "DLQ delays processing for bad messages (operational toil). Strict validation rejects valid edge cases if schema too tight. Example: Kafka consumer OOM on 12MB JSON → partition stuck. Move to DLQ; fix deserializer; replay with size cap. Name metric + revisit trigger when they push depth.", "trade_html": "DLQ delays processing for bad messages (operational toil). Strict validation rejects valid edge cases if schema too tight.", "example_html": "<em>Kafka consumer OOM on 12MB JSON → partition stuck. Move to DLQ; fix deserializer; replay with size cap.</em>", "visual_html": "<a href=\"#poison-message\" class=\"diag-link\" data-diag=\"poison-message\">Poison message</a>", "java_html": "", "java": ""}, {"title": "Head-of-line blocking", "slug": "head-of-line-blocking", "problem": "One slow message blocks the entire queue — how do you prevent head-of-line blocking?", "weak": "One worker pool for all job types.", "staff": "One slow item blocks entire queue (FIFO worker stuck on huge job). Use **multiple queues by SLA**, **priority queues**, **separate thread pools per task type**, **bounded work stealing**. For HTTP: don't share one pool between fast reads and slow reports.", "staff_plus": "More queues = more ops complexity and potential starvation of low-priority work. Priority inversion if not careful with shared resources. Example: Video transcode 40 min blocks thumbnail job. Dedicated `fast` and `slow` Kafka topics. Name metric + revisit trigger when they push depth.", "trade": "More queues = more ops complexity and potential starvation of low-priority work. Priority inversion if not careful with shared resources.", "example": "*Video transcode 40 min blocks thumbnail job. Dedicated `fast` and `slow` Kafka topics.*", "visual": "[Poison message](interview-quick-fire.html#poison-message) *(split fast/slow queues)*", "java_blocks": [], "severity": "critical", "problem_html": "One slow message blocks the entire queue — how do you prevent head-of-line blocking?", "weak_html": "One worker pool for all job types.", "staff_html": "One slow item blocks entire queue (FIFO worker stuck on huge job). Use <strong>multiple queues by SLA</strong>, <strong>priority queues</strong>, <strong>separate thread pools per task type</strong>, <strong>bounded work stealing</strong>. For HTTP: don't share one pool between fast reads and slow reports.", "staff_plus_html": "More queues = more ops complexity and potential starvation of low-priority work. Priority inversion if not careful with shared resources. Example: Video transcode 40 min blocks thumbnail job. Dedicated <code>fast</code> and <code>slow</code> Kafka topics. Name metric + revisit trigger when they push depth.", "trade_html": "More queues = more ops complexity and potential starvation of low-priority work. Priority inversion if not careful with shared resources.", "example_html": "<em>Video transcode 40 min blocks thumbnail job. Dedicated <code>fast</code> and <code>slow</code> Kafka topics.</em>", "visual_html": "<a href=\"#poison-message\" class=\"diag-link\" data-diag=\"poison-message\">Poison message</a> <em>(split fast/slow queues)</em>", "java_html": "", "java": ""}, {"title": "N+1 queries", "slug": "n1-queries", "problem": "Your API runs one DB query per item in a list — how do you fix the N+1 problem?", "weak": "Load related rows in a loop — simple and correct.", "staff": "Loop loads parent rows then one query per child — collapses at scale. Fix with **JOIN + batch load**, **DataLoader pattern** (batch IDs per request), **denormalized read model** for hot paths. In microservices: **graphQL batch endpoint** or materialized view — not 50 sequential RPCs.", "staff_plus": "JOINs couple schemas; denormalization adds sync lag. Batching adds latency within single request (wait for batch window). Example: Feed loads 500 authors each with a profile query → 501 DB roundtrips. Batch `WHERE id IN (...)`. Name metric + revisit trigger when they push depth.", "trade": "JOINs couple schemas; denormalization adds sync lag. Batching adds latency within single request (wait for batch window).", "example": "*Feed loads 500 authors each with a profile query → 501 DB roundtrips. Batch `WHERE id IN (...)`.*", "visual": "[N+1 vs batch](interview-quick-fire.html#n1-batch)", "java_blocks": [], "severity": "critical", "problem_html": "Your API runs one DB query per item in a list — how do you fix the N+1 problem?", "weak_html": "Load related rows in a loop — simple and correct.", "staff_html": "Loop loads parent rows then one query per child — collapses at scale. Fix with <strong>JOIN + batch load</strong>, <strong>DataLoader pattern</strong> (batch IDs per request), <strong>denormalized read model</strong> for hot paths. In microservices: <strong>graphQL batch endpoint</strong> or materialized view — not 50 sequential RPCs.", "staff_plus_html": "JOINs couple schemas; denormalization adds sync lag. Batching adds latency within single request (wait for batch window). Example: Feed loads 500 authors each with a profile query → 501 DB roundtrips. Batch <code>WHERE id IN (...)</code>. Name metric + revisit trigger when they push depth.", "trade_html": "JOINs couple schemas; denormalization adds sync lag. Batching adds latency within single request (wait for batch window).", "example_html": "<em>Feed loads 500 authors each with a profile query → 501 DB roundtrips. Batch <code>WHERE id IN (...)</code>.</em>", "visual_html": "<a href=\"#n1-batch\" class=\"diag-link\" data-diag=\"n1-batch\">N+1 vs batch</a>", "java_html": "", "java": ""}, {"title": "Connection pool exhaustion", "slug": "connection-pool-exhaustion", "problem": "Under load your app runs out of database connections — what is going wrong?", "weak": "Increase max connections on the database.", "staff": "App holds DB connections too long (slow queries, missing `finally close`, transaction scope too wide). **Right-size pool** (often tens, not thousands per instance), **query timeouts**, **pgbouncer/RDS proxy** for multiplexing, **reject** when pool saturated instead of queuing forever. Monitor **waiting thread count**.", "staff_plus": "Small pools limit per-instance throughput — scale horizontally instead. Proxy adds hop latency and single point of failure if not HA. Example: Deploy leak leaves connections open → new requests hang 30s. Alert on `pool.waiting > 0`. Name metric + revisit trigger when they push depth.", "trade": "Small pools limit per-instance throughput — scale horizontally instead. Proxy adds hop latency and single point of failure if not HA.", "example": "*Deploy leak leaves connections open → new requests hang 30s. Alert on `pool.waiting > 0`.*", "visual": "[Connection pool](interview-quick-fire.html#connection-pool)", "java_blocks": [], "severity": "critical", "problem_html": "Under load your app runs out of database connections — what is going wrong?", "weak_html": "Increase max connections on the database.", "staff_html": "App holds DB connections too long (slow queries, missing <code>finally close</code>, transaction scope too wide). <strong>Right-size pool</strong> (often tens, not thousands per instance), <strong>query timeouts</strong>, <strong>pgbouncer/RDS proxy</strong> for multiplexing, <strong>reject</strong> when pool saturated instead of queuing forever. Monitor <strong>waiting thread count</strong>.", "staff_plus_html": "Small pools limit per-instance throughput — scale horizontally instead. Proxy adds hop latency and single point of failure if not HA. Example: Deploy leak leaves connections open → new requests hang 30s. Alert on <code>pool.waiting > 0</code>. Name metric + revisit trigger when they push depth.", "trade_html": "Small pools limit per-instance throughput — scale horizontally instead. Proxy adds hop latency and single point of failure if not HA.", "example_html": "<em>Deploy leak leaves connections open → new requests hang 30s. Alert on <code>pool.waiting > 0</code>.</em>", "visual_html": "<a href=\"#connection-pool\" class=\"diag-link\" data-diag=\"connection-pool\">Connection pool</a>", "java_html": "", "java": ""}, {"title": "Replica lag / stale read", "slug": "replica-lag-stale-read", "problem": "A user updates data but immediately reads the old value from a replica — how do you handle lag?", "weak": "Add read replicas and route all reads there.", "staff": "Read replica serves data seconds behind primary — user sees own write missing. **Route read-your-writes to primary** (or sticky session), **monitor replication lag** and drop replica from pool if > threshold, **version tokens** in API so client knows staleness.", "staff_plus": "Primary reads reduce scale benefit of replicas. Lag threshold tuning is workload-specific (feeds OK, banking not). Example: User posts comment, refresh shows nothing — read hit 30s-lagged replica. Session stickiness to primary for 5s after write. Name metric + revisit trigger when they push depth.", "trade": "Primary reads reduce scale benefit of replicas. Lag threshold tuning is workload-specific (feeds OK, banking not).", "example": "*User posts comment, refresh shows nothing — read hit 30s-lagged replica. Session stickiness to primary for 5s after write.*", "visual": "[Replica lag](interview-quick-fire.html#replica-lag)", "java_blocks": [], "severity": "critical", "problem_html": "A user updates data but immediately reads the old value from a replica — how do you handle lag?", "weak_html": "Add read replicas and route all reads there.", "staff_html": "Read replica serves data seconds behind primary — user sees own write missing. <strong>Route read-your-writes to primary</strong> (or sticky session), <strong>monitor replication lag</strong> and drop replica from pool if > threshold, <strong>version tokens</strong> in API so client knows staleness.", "staff_plus_html": "Primary reads reduce scale benefit of replicas. Lag threshold tuning is workload-specific (feeds OK, banking not). Example: User posts comment, refresh shows nothing — read hit 30s-lagged replica. Session stickiness to primary for 5s after write. Name metric + revisit trigger when they push depth.", "trade_html": "Primary reads reduce scale benefit of replicas. Lag threshold tuning is workload-specific (feeds OK, banking not).", "example_html": "<em>User posts comment, refresh shows nothing — read hit 30s-lagged replica. Session stickiness to primary for 5s after write.</em>", "visual_html": "<a href=\"#replica-lag\" class=\"diag-link\" data-diag=\"replica-lag\">Replica lag</a>", "java_html": "", "java": ""}, {"title": "Slow node (straggler)", "slug": "slow-node-straggler", "problem": "One node in a scatter-gather query is 10× slower — how do you limit tail latency?", "weak": "Wait for the slowest shard — correctness first.", "staff": "One shard/node at 99th percentile kills scatter-gather (MapReduce, multi-shard query). **Speculative duplicate requests** (hedged reads), **timeout per shard** and return partial results, **rebalance** hot nodes, **avoid co-tenancy** of heavy tenants.", "staff_plus": "Hedged reads double load on recovery path. Partial results complicate API contract. Example: ES query across 20 shards; one shard on noisy neighbor → p99 3s. Cancel straggler at 500ms; return 19/20. Name metric + revisit trigger when they push depth.", "trade": "Hedged reads double load on recovery path. Partial results complicate API contract.", "example": "*ES query across 20 shards; one shard on noisy neighbor → p99 3s. Cancel straggler at 500ms; return 19/20.*", "visual": "[Scatter-gather straggler](interview-quick-fire.html#straggler)", "java_blocks": [], "severity": "critical", "problem_html": "One node in a scatter-gather query is 10× slower — how do you limit tail latency?", "weak_html": "Wait for the slowest shard — correctness first.", "staff_html": "One shard/node at 99th percentile kills scatter-gather (MapReduce, multi-shard query). <strong>Speculative duplicate requests</strong> (hedged reads), <strong>timeout per shard</strong> and return partial results, <strong>rebalance</strong> hot nodes, <strong>avoid co-tenancy</strong> of heavy tenants.", "staff_plus_html": "Hedged reads double load on recovery path. Partial results complicate API contract. Example: ES query across 20 shards; one shard on noisy neighbor → p99 3s. Cancel straggler at 500ms; return 19/20. Name metric + revisit trigger when they push depth.", "trade_html": "Hedged reads double load on recovery path. Partial results complicate API contract.", "example_html": "<em>ES query across 20 shards; one shard on noisy neighbor → p99 3s. Cancel straggler at 500ms; return 19/20.</em>", "visual_html": "<a href=\"#straggler\" class=\"diag-link\" data-diag=\"straggler\">Scatter-gather straggler</a>", "java_html": "", "java": ""}, {"title": "Dual-write problem", "slug": "dual-write-problem", "problem": "You write to the database and search index separately and they drift — how do you keep them in sync?", "weak": "Write to DB and cache in the same request handler.", "staff": "Writing to DB and cache (or ES) in application code without atomicity — crash between writes causes permanent drift. Prefer **CDC / transactional outbox** → async projector updates derived store. Cache: **cache-aside** with DB as source of truth, not write-through from app dual paths.", "staff_plus": "CDC adds lag to search index. Outbox requires consumer ops. Cache-aside has miss path complexity. Example: Write PG succeeds, ES write fails — search missing new row until nightly rebuild. Outbox + indexer. Name metric + revisit trigger when they push depth.", "trade": "CDC adds lag to search index. Outbox requires consumer ops. Cache-aside has miss path complexity.", "example": "*Write PG succeeds, ES write fails — search missing new row until nightly rebuild. Outbox + indexer.*", "visual": "[Dual-write vs outbox](interview-quick-fire.html#dual-write)", "java_blocks": [], "severity": "critical", "problem_html": "You write to the database and search index separately and they drift — how do you keep them in sync?", "weak_html": "Write to DB and cache in the same request handler.", "staff_html": "Writing to DB and cache (or ES) in application code without atomicity — crash between writes causes permanent drift. Prefer <strong>CDC / transactional outbox</strong> → async projector updates derived store. Cache: <strong>cache-aside</strong> with DB as source of truth, not write-through from app dual paths.", "staff_plus_html": "CDC adds lag to search index. Outbox requires consumer ops. Cache-aside has miss path complexity. Example: Write PG succeeds, ES write fails — search missing new row until nightly rebuild. Outbox + indexer. Name metric + revisit trigger when they push depth.", "trade_html": "CDC adds lag to search index. Outbox requires consumer ops. Cache-aside has miss path complexity.", "example_html": "<em>Write PG succeeds, ES write fails — search missing new row until nightly rebuild. Outbox + indexer.</em>", "visual_html": "<a href=\"#dual-write\" class=\"diag-link\" data-diag=\"dual-write\">Dual-write vs outbox</a>", "java_html": "", "java": ""}, {"title": "Circular dependency / retry loop", "slug": "circular-dependency-retry-loop", "problem": "Service A calls B, B calls A, and retries create a loop — how do you break it?", "weak": "Service A calls B calls A with retries enabled.", "staff": "Service A calls B calls A, or retry policies form a loop under failure. **Timeouts + max depth headers**, **acyclic dependency rules** in architecture review, **async handoff** at boundaries. Break sync cycles with queue.", "staff_plus": "Async adds UX latency for completion. Strict layering can feel bureaucratic but prevents outage amplification. Example: Auth service calls User service calls Auth for permission — deadlock under load. Extract permissions cache. Name metric + revisit trigger when they push depth.", "trade": "Async adds UX latency for completion. Strict layering can feel bureaucratic but prevents outage amplification.", "example": "*Auth service calls User service calls Auth for permission — deadlock under load. Extract permissions cache.*", "visual": "[Retry storm](interview-quick-fire.html#retry-storm) *(draw A→B→A cycle; break with queue)*", "java_blocks": [], "severity": "critical", "problem_html": "Service A calls B, B calls A, and retries create a loop — how do you break it?", "weak_html": "Service A calls B calls A with retries enabled.", "staff_html": "Service A calls B calls A, or retry policies form a loop under failure. <strong>Timeouts + max depth headers</strong>, <strong>acyclic dependency rules</strong> in architecture review, <strong>async handoff</strong> at boundaries. Break sync cycles with queue.", "staff_plus_html": "Async adds UX latency for completion. Strict layering can feel bureaucratic but prevents outage amplification. Example: Auth service calls User service calls Auth for permission — deadlock under load. Extract permissions cache. Name metric + revisit trigger when they push depth.", "trade_html": "Async adds UX latency for completion. Strict layering can feel bureaucratic but prevents outage amplification.", "example_html": "<em>Auth service calls User service calls Auth for permission — deadlock under load. Extract permissions cache.</em>", "visual_html": "<a href=\"#retry-storm\" class=\"diag-link\" data-diag=\"retry-storm\">Retry storm</a> <em>(draw A→B→A cycle; break with queue)</em>", "java_html": "", "java": ""}]}, {"title": "Availability & resilience", "slug": "availability-resilience", "severity": "high", "patterns": [{"title": "Handle traffic spikes", "slug": "handle-traffic-spikes", "problem": "Traffic spikes 10× during a flash event — how do you absorb it without downtime?", "weak": "Autoscale app servers; the DB will keep up.", "staff": "**Stateless** app tier behind LB + **autoscale** on CPU/RPS/queue depth. **Absorb burst** in Kafka/SQS. **Circuit breakers** on downstreams. **Rate limit** at edge before origin melts.", "staff_plus": "Autoscale lags minutes — need buffer (queue) or pre-warming for known events. Breakers cause errors for edge cases during recovery. Example: Shopify Black Friday — checkout writes queued; read path scaled horizontally. Name metric + revisit trigger when they push depth.", "trade": "Autoscale lags minutes — need buffer (queue) or pre-warming for known events. Breakers cause errors for edge cases during recovery.", "example": "*Shopify Black Friday — checkout writes queued; read path scaled horizontally.*", "visual": "", "java_blocks": [], "severity": "high", "problem_html": "Traffic spikes 10× during a flash event — how do you absorb it without downtime?", "weak_html": "Autoscale app servers; the DB will keep up.", "staff_html": "<strong>Stateless</strong> app tier behind LB + <strong>autoscale</strong> on CPU/RPS/queue depth. <strong>Absorb burst</strong> in Kafka/SQS. <strong>Circuit breakers</strong> on downstreams. <strong>Rate limit</strong> at edge before origin melts.", "staff_plus_html": "Autoscale lags minutes — need buffer (queue) or pre-warming for known events. Breakers cause errors for edge cases during recovery. Example: Shopify Black Friday — checkout writes queued; read path scaled horizontally. Name metric + revisit trigger when they push depth.", "trade_html": "Autoscale lags minutes — need buffer (queue) or pre-warming for known events. Breakers cause errors for edge cases during recovery.", "example_html": "<em>Shopify Black Friday — checkout writes queued; read path scaled horizontally.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Eliminate single point of failure", "slug": "eliminate-single-point-of-failure", "problem": "Walk me through how you would remove single points of failure in this design.", "weak": "Run two of everything in one AZ.", "staff": "Redundancy at **every** tier: 2+ LBs (anycast or DNS failover), N app instances, DB **primary + sync replica**, Redis **primary + replica**, multi-AZ. **Health checks** remove unhealthy targets; **chaos drills** prove it works.", "staff_plus": "Cost doubles (or more). Split-brain risk if failover automation wrong. Complexity of active-active vs active-passive. Example: RDS Multi-AZ — sync standby promotion on primary failure. Name metric + revisit trigger when they push depth.", "trade": "Cost doubles (or more). Split-brain risk if failover automation wrong. Complexity of active-active vs active-passive.", "example": "*RDS Multi-AZ — sync standby promotion on primary failure.*", "visual": "", "java_blocks": [], "severity": "high", "problem_html": "Walk me through how you would remove single points of failure in this design.", "weak_html": "Run two of everything in one AZ.", "staff_html": "Redundancy at <strong>every</strong> tier: 2+ LBs (anycast or DNS failover), N app instances, DB <strong>primary + sync replica</strong>, Redis <strong>primary + replica</strong>, multi-AZ. <strong>Health checks</strong> remove unhealthy targets; <strong>chaos drills</strong> prove it works.", "staff_plus_html": "Cost doubles (or more). Split-brain risk if failover automation wrong. Complexity of active-active vs active-passive. Example: RDS Multi-AZ — sync standby promotion on primary failure. Name metric + revisit trigger when they push depth.", "trade_html": "Cost doubles (or more). Split-brain risk if failover automation wrong. Complexity of active-active vs active-passive.", "example_html": "<em>RDS Multi-AZ — sync standby promotion on primary failure.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "DB primary fails", "slug": "db-primary-fails", "problem": "Your database primary goes down — what is your failover and recovery plan?", "weak": "Manual failover when someone pages you.", "staff": "Automated **failover** to sync replica (Orchestrator, Patroni, RDS Multi-AZ). Apps use **DNS/connection string** that updates or **proxy** (PgBouncer, RDS Proxy). **Retry with backoff** on transient connection errors.", "staff_plus": "Failover takes 15–60s — in-flight transactions fail. Sync replica lag = data loss window if async (unacceptable for money). Example: Payments — sync replication only; accept unavailable during AZ failure, not wrong balance. Name metric + revisit trigger when they push depth.", "trade": "Failover takes 15–60s — in-flight transactions fail. Sync replica lag = data loss window if async (unacceptable for money).", "example": "*Payments — sync replication only; accept unavailable during AZ failure, not wrong balance.*", "visual": "", "java_blocks": [], "severity": "high", "problem_html": "Your database primary goes down — what is your failover and recovery plan?", "weak_html": "Manual failover when someone pages you.", "staff_html": "Automated <strong>failover</strong> to sync replica (Orchestrator, Patroni, RDS Multi-AZ). Apps use <strong>DNS/connection string</strong> that updates or <strong>proxy</strong> (PgBouncer, RDS Proxy). <strong>Retry with backoff</strong> on transient connection errors.", "staff_plus_html": "Failover takes 15–60s — in-flight transactions fail. Sync replica lag = data loss window if async (unacceptable for money). Example: Payments — sync replication only; accept unavailable during AZ failure, not wrong balance. Name metric + revisit trigger when they push depth.", "trade_html": "Failover takes 15–60s — in-flight transactions fail. Sync replica lag = data loss window if async (unacceptable for money).", "example_html": "<em>Payments — sync replication only; accept unavailable during AZ failure, not wrong balance.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Cascading failure", "slug": "cascading-failure", "problem": "One service failure takes down everything downstream — how do you stop cascading failures?", "weak": "Retry until downstream recovers.", "staff": "**Timeouts** < client deadline everywhere. **Bulkheads** (separate pools for critical vs batch). **Circuit breakers** stop calling sick deps. **Load shed** non-critical endpoints first (recommendations off, core checkout on).", "staff_plus": "Shedding angers users on deprioritized features. Tight timeouts cause false failures on slow but healthy deps — tune per dependency. Example: Netflix Hystrix-era pattern — fallback static list when recommendation service down. Name metric + revisit trigger when they push depth.", "trade": "Shedding angers users on deprioritized features. Tight timeouts cause false failures on slow but healthy deps — tune per dependency.", "example": "*Netflix Hystrix-era pattern — fallback static list when recommendation service down.*", "visual": "[Retry storm](interview-quick-fire.html#retry-storm)", "java_blocks": [], "severity": "high", "problem_html": "One service failure takes down everything downstream — how do you stop cascading failures?", "weak_html": "Retry until downstream recovers.", "staff_html": "<strong>Timeouts</strong> < client deadline everywhere. <strong>Bulkheads</strong> (separate pools for critical vs batch). <strong>Circuit breakers</strong> stop calling sick deps. <strong>Load shed</strong> non-critical endpoints first (recommendations off, core checkout on).", "staff_plus_html": "Shedding angers users on deprioritized features. Tight timeouts cause false failures on slow but healthy deps — tune per dependency. Example: Netflix Hystrix-era pattern — fallback static list when recommendation service down. Name metric + revisit trigger when they push depth.", "trade_html": "Shedding angers users on deprioritized features. Tight timeouts cause false failures on slow but healthy deps — tune per dependency.", "example_html": "<em>Netflix Hystrix-era pattern — fallback static list when recommendation service down.</em>", "visual_html": "<a href=\"#retry-storm\" class=\"diag-link\" data-diag=\"retry-storm\">Retry storm</a>", "java_html": "", "java": ""}, {"title": "Regional outage", "slug": "regional-outage", "problem": "An entire cloud region goes offline — how does your system stay available?", "weak": "Multi-region active-active from day one.", "staff": "**Multi-region** deployment with GeoDNS failover. Define **RPO/RTO** per service. **Active-passive** for strong consistency workloads; **active-active** only with conflict resolution story.", "staff_plus": "Active-active cross-region writes need CRDTs, last-write-wins, or partitioned tenants. Failover drills required — DNS TTL stalls traffic shift. Example: S3 cross-region replication for media; API active-passive with Route53 health checks. Name metric + revisit trigger when they push depth.", "trade": "Active-active cross-region writes need CRDTs, last-write-wins, or partitioned tenants. Failover drills required — DNS TTL stalls traffic shift.", "example": "*S3 cross-region replication for media; API active-passive with Route53 health checks.*", "visual": "", "java_blocks": [], "severity": "high", "problem_html": "An entire cloud region goes offline — how does your system stay available?", "weak_html": "Multi-region active-active from day one.", "staff_html": "<strong>Multi-region</strong> deployment with GeoDNS failover. Define <strong>RPO/RTO</strong> per service. <strong>Active-passive</strong> for strong consistency workloads; <strong>active-active</strong> only with conflict resolution story.", "staff_plus_html": "Active-active cross-region writes need CRDTs, last-write-wins, or partitioned tenants. Failover drills required — DNS TTL stalls traffic shift. Example: S3 cross-region replication for media; API active-passive with Route53 health checks. Name metric + revisit trigger when they push depth.", "trade_html": "Active-active cross-region writes need CRDTs, last-write-wins, or partitioned tenants. Failover drills required — DNS TTL stalls traffic shift.", "example_html": "<em>S3 cross-region replication for media; API active-passive with Route53 health checks.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Zero-downtime deploy", "slug": "zero-downtime-deploy", "problem": "How do you deploy new code without taking the service offline?", "weak": "Rolling restart — users won't notice brief errors.", "staff": "**Rolling deploy** behind LB (drain connections). **Readiness vs liveness** probes. **Feature flags** for risky code paths. **Blue-green** or **canary** (1% traffic) with automatic rollback on error budget burn.", "staff_plus": "Two versions running during rollout — schema must be backward compatible. Canary needs traffic routing infra. Example: Kubernetes rolling update `maxUnavailable: 0` + PDB. Name metric + revisit trigger when they push depth.", "trade": "Two versions running during rollout — schema must be backward compatible. Canary needs traffic routing infra.", "example": "*Kubernetes rolling update `maxUnavailable: 0` + PDB.*", "visual": "", "java_blocks": [], "severity": "high", "problem_html": "How do you deploy new code without taking the service offline?", "weak_html": "Rolling restart — users won't notice brief errors.", "staff_html": "<strong>Rolling deploy</strong> behind LB (drain connections). <strong>Readiness vs liveness</strong> probes. <strong>Feature flags</strong> for risky code paths. <strong>Blue-green</strong> or <strong>canary</strong> (1% traffic) with automatic rollback on error budget burn.", "staff_plus_html": "Two versions running during rollout — schema must be backward compatible. Canary needs traffic routing infra. Example: Kubernetes rolling update <code>maxUnavailable: 0</code> + PDB. Name metric + revisit trigger when they push depth.", "trade_html": "Two versions running during rollout — schema must be backward compatible. Canary needs traffic routing infra.", "example_html": "<em>Kubernetes rolling update <code>maxUnavailable: 0</code> + PDB.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Reads & caching", "slug": "reads-caching", "severity": "pattern", "patterns": [{"title": "Reduce DB read load", "slug": "reduce-db-read-load", "problem": "Reads are hammering your database — how do you reduce read load on the primary?", "weak": "Put Redis in front of the database.", "staff": "**Read replicas** for fan-out; **Redis cache-aside** for hot keys (app reads cache → on miss read DB → populate). Target **>90% hit rate** on read-heavy paths. **Invalidate or TTL** on write; never treat cache as source of truth.", "staff_plus": "Replica lag → stale reads unless you route critical reads to primary. Cache invalidation bugs cause subtle data bugs. Memory cost scales with working set. Example: Netflix ~95% API traffic served from EVCache/Memcached layer. Name metric + revisit trigger when they push depth.", "trade": "Replica lag → stale reads unless you route critical reads to primary. Cache invalidation bugs cause subtle data bugs. Memory cost scales with working set.", "example": "*Netflix ~95% API traffic served from EVCache/Memcached layer.*", "visual": "[Cache-aside](interview-quick-fire.html#cache-aside)", "java_blocks": [], "severity": "pattern", "problem_html": "Reads are hammering your database — how do you reduce read load on the primary?", "weak_html": "Put Redis in front of the database.", "staff_html": "<strong>Read replicas</strong> for fan-out; <strong>Redis cache-aside</strong> for hot keys (app reads cache → on miss read DB → populate). Target <strong>>90% hit rate</strong> on read-heavy paths. <strong>Invalidate or TTL</strong> on write; never treat cache as source of truth.", "staff_plus_html": "Replica lag → stale reads unless you route critical reads to primary. Cache invalidation bugs cause subtle data bugs. Memory cost scales with working set. Example: Netflix ~95% API traffic served from EVCache/Memcached layer. Name metric + revisit trigger when they push depth.", "trade_html": "Replica lag → stale reads unless you route critical reads to primary. Cache invalidation bugs cause subtle data bugs. Memory cost scales with working set.", "example_html": "<em>Netflix ~95% API traffic served from EVCache/Memcached layer.</em>", "visual_html": "<a href=\"#cache-aside\" class=\"diag-link\" data-diag=\"cache-aside\">Cache-aside</a>", "java_html": "", "java": ""}, {"title": "Hot key / viral content", "slug": "hot-key-viral-content", "problem": "A viral post makes one cache key receive millions of reads per second — what do you do?", "weak": "Bigger Redis instance when a celebrity posts.", "staff": "Three layers: **local LRU** (microseconds, per process) → **Redis cluster** (milliseconds) → **DB/CDN**. Instrument per-key QPS; alert at 1K RPS/key. For global counters use **sharded counters** or **HyperLogLog** if approximate OK.", "staff_plus": "Local cache = inconsistent across fleet. Sharded counters lose O(1) global exact count. CDN caching of dynamic data needs short TTL + purge playbook. Example: Viral Bitly link — single Redis key melts. Local LRU + CDN 302 caching for top-N URLs. Name metric + revisit trigger when they push depth.", "trade": "Local cache = inconsistent across fleet. Sharded counters lose O(1) global exact count. CDN caching of dynamic data needs short TTL + purge playbook.", "example": "*Viral Bitly link — single Redis key melts. Local LRU + CDN 302 caching for top-N URLs.*", "visual": "[Hot key](interview-quick-fire.html#hot-key)", "java_blocks": [], "severity": "pattern", "problem_html": "A viral post makes one cache key receive millions of reads per second — what do you do?", "weak_html": "Bigger Redis instance when a celebrity posts.", "staff_html": "Three layers: <strong>local LRU</strong> (microseconds, per process) → <strong>Redis cluster</strong> (milliseconds) → <strong>DB/CDN</strong>. Instrument per-key QPS; alert at 1K RPS/key. For global counters use <strong>sharded counters</strong> or <strong>HyperLogLog</strong> if approximate OK.", "staff_plus_html": "Local cache = inconsistent across fleet. Sharded counters lose O(1) global exact count. CDN caching of dynamic data needs short TTL + purge playbook. Example: Viral Bitly link — single Redis key melts. Local LRU + CDN 302 caching for top-N URLs. Name metric + revisit trigger when they push depth.", "trade_html": "Local cache = inconsistent across fleet. Sharded counters lose O(1) global exact count. CDN caching of dynamic data needs short TTL + purge playbook.", "example_html": "<em>Viral Bitly link — single Redis key melts. Local LRU + CDN 302 caching for top-N URLs.</em>", "visual_html": "<a href=\"#hot-key\" class=\"diag-link\" data-diag=\"hot-key\">Hot key</a>", "java_html": "", "java": ""}, {"title": "Stale cache after update", "slug": "stale-cache-after-update", "problem": "Users see stale data after an update because the cache was not invalidated — how do you fix it?", "weak": "Delete cache key on every write — always consistent.", "staff": "**Write-invalidate** (delete cache key on mutation) or **write-through** for low-cardinality entities. TTL as safety net only. For feeds, expose **version / `updated_at`** so UI can reconcile.", "staff_plus": "Invalidate on every write reduces hit rate for churny keys. Write-through adds write latency. Versioned UI adds client complexity. Example: Profile name change — `DEL user:123` in Redis on PG commit. Name metric + revisit trigger when they push depth.", "trade": "Invalidate on every write reduces hit rate for churny keys. Write-through adds write latency. Versioned UI adds client complexity.", "example": "*Profile name change — `DEL user:123` in Redis on PG commit.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "Users see stale data after an update because the cache was not invalidated — how do you fix it?", "weak_html": "Delete cache key on every write — always consistent.", "staff_html": "<strong>Write-invalidate</strong> (delete cache key on mutation) or <strong>write-through</strong> for low-cardinality entities. TTL as safety net only. For feeds, expose <strong>version / <code>updated_at</code></strong> so UI can reconcile.", "staff_plus_html": "Invalidate on every write reduces hit rate for churny keys. Write-through adds write latency. Versioned UI adds client complexity. Example: Profile name change — <code>DEL user:123</code> in Redis on PG commit. Name metric + revisit trigger when they push depth.", "trade_html": "Invalidate on every write reduces hit rate for churny keys. Write-through adds write latency. Versioned UI adds client complexity.", "example_html": "<em>Profile name change — <code>DEL user:123</code> in Redis on PG commit.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Reduce global read latency", "slug": "reduce-global-read-latency", "problem": "Users in Asia see 800ms latency reading from your US database — how do you reduce global latency?", "weak": "Deploy one big CDN in the US — covers everyone.", "staff": "**CDN** for static and cacheable API responses. **GeoDNS / latency-based routing** to nearest region. **Read replicas per region** with async replication; accept staleness or conflict rules for multi-master.", "staff_plus": "Multi-region consistency is hard (CAP). CDN cache invalidation is slow and costs money. Data residency laws may forbid cross-border copies. Example: Cloudflare 300+ PoPs; HLS video segments `max-age=86400`. Name metric + revisit trigger when they push depth.", "trade": "Multi-region consistency is hard (CAP). CDN cache invalidation is slow and costs money. Data residency laws may forbid cross-border copies.", "example": "*Cloudflare 300+ PoPs; HLS video segments `max-age=86400`.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "Users in Asia see 800ms latency reading from your US database — how do you reduce global latency?", "weak_html": "Deploy one big CDN in the US — covers everyone.", "staff_html": "<strong>CDN</strong> for static and cacheable API responses. <strong>GeoDNS / latency-based routing</strong> to nearest region. <strong>Read replicas per region</strong> with async replication; accept staleness or conflict rules for multi-master.", "staff_plus_html": "Multi-region consistency is hard (CAP). CDN cache invalidation is slow and costs money. Data residency laws may forbid cross-border copies. Example: Cloudflare 300+ PoPs; HLS video segments <code>max-age=86400</code>. Name metric + revisit trigger when they push depth.", "trade_html": "Multi-region consistency is hard (CAP). CDN cache invalidation is slow and costs money. Data residency laws may forbid cross-border copies.", "example_html": "<em>Cloudflare 300+ PoPs; HLS video segments <code>max-age=86400</code>.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Pagination at scale", "slug": "pagination-at-scale", "problem": "OFFSET pagination gets slower as users page deeper — how do you paginate at scale?", "weak": "OFFSET/LIMIT — page 10,000 is fine if indexed.", "staff": "**Keyset / cursor** pagination (`WHERE (ts, id) < cursor ORDER BY ts DESC LIMIT 20`). Never `OFFSET` on large tables — O(n) scans. Cursor is opaque blob encoding last seen tuple.", "staff_plus": "No \"jump to page 47\" without walking cursors. Stable sort key required; composite index design matters. Example: Twitter timelines — snowflake ID as cursor, not page numbers. Name metric + revisit trigger when they push depth.", "trade": "No \"jump to page 47\" without walking cursors. Stable sort key required; composite index design matters.", "example": "*Twitter timelines — snowflake ID as cursor, not page numbers.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "OFFSET pagination gets slower as users page deeper — how do you paginate at scale?", "weak_html": "OFFSET/LIMIT — page 10,000 is fine if indexed.", "staff_html": "<strong>Keyset / cursor</strong> pagination (<code>WHERE (ts, id) < cursor ORDER BY ts DESC LIMIT 20</code>). Never <code>OFFSET</code> on large tables — O(n) scans. Cursor is opaque blob encoding last seen tuple.", "staff_plus_html": "No "jump to page 47" without walking cursors. Stable sort key required; composite index design matters. Example: Twitter timelines — snowflake ID as cursor, not page numbers. Name metric + revisit trigger when they push depth.", "trade_html": "No "jump to page 47" without walking cursors. Stable sort key required; composite index design matters.", "example_html": "<em>Twitter timelines — snowflake ID as cursor, not page numbers.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Search across billions of records", "slug": "search-across-billions-of-records", "problem": "How would you build full-text search across billions of documents?", "weak": "SELECT * WHERE title LIKE '%query%'.", "staff": "**Elasticsearch** (or similar) as **derived index**. Ingest via CDC (Debezium) or dual-write outbox. Primary DB remains source of truth; ES rebuilt from snapshot + CDC if lost.", "staff_plus": "Index lag (seconds). Denormalized docs drift from normalized DB. Cluster ops and mapping migrations are non-trivial. Example: Shopify product search — PG → Kafka → ES; rebuild index from PG snapshot overnight. Name metric + revisit trigger when they push depth.", "trade": "Index lag (seconds). Denormalized docs drift from normalized DB. Cluster ops and mapping migrations are non-trivial.", "example": "*Shopify product search — PG → Kafka → ES; rebuild index from PG snapshot overnight.*", "visual": "[Dual-write vs outbox](interview-quick-fire.html#dual-write)", "java_blocks": [], "severity": "pattern", "problem_html": "How would you build full-text search across billions of documents?", "weak_html": "SELECT * WHERE title LIKE '%query%'.", "staff_html": "<strong>Elasticsearch</strong> (or similar) as <strong>derived index</strong>. Ingest via CDC (Debezium) or dual-write outbox. Primary DB remains source of truth; ES rebuilt from snapshot + CDC if lost.", "staff_plus_html": "Index lag (seconds). Denormalized docs drift from normalized DB. Cluster ops and mapping migrations are non-trivial. Example: Shopify product search — PG → Kafka → ES; rebuild index from PG snapshot overnight. Name metric + revisit trigger when they push depth.", "trade_html": "Index lag (seconds). Denormalized docs drift from normalized DB. Cluster ops and mapping migrations are non-trivial.", "example_html": "<em>Shopify product search — PG → Kafka → ES; rebuild index from PG snapshot overnight.</em>", "visual_html": "<a href=\"#dual-write\" class=\"diag-link\" data-diag=\"dual-write\">Dual-write vs outbox</a>", "java_html": "", "java": ""}, {"title": "Autocomplete / typeahead", "slug": "autocomplete-typeahead", "problem": "Design autocomplete that returns suggestions within 50ms as the user types.", "weak": "Prefix scan on the users table on every keystroke.", "staff": "Offline **MapReduce** on query logs → **prefix → top-K** in Redis. Online path: debounce 100ms, `HGET prefix`, CDN for top 10K prefixes. Fuzzy match optional second tier (ES).", "staff_plus": "Weekly rebuild = stale trending queries. Top-K only — no full corpus scan at keystroke. Privacy: aggregate logs, don't store raw PII queries. Example: Google Suggest — precomputed trie shards + aggressive CDN. Name metric + revisit trigger when they push depth.", "trade": "Weekly rebuild = stale trending queries. Top-K only — no full corpus scan at keystroke. Privacy: aggregate logs, don't store raw PII queries.", "example": "*Google Suggest — precomputed trie shards + aggressive CDN.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "Design autocomplete that returns suggestions within 50ms as the user types.", "weak_html": "Prefix scan on the users table on every keystroke.", "staff_html": "Offline <strong>MapReduce</strong> on query logs → <strong>prefix → top-K</strong> in Redis. Online path: debounce 100ms, <code>HGET prefix</code>, CDN for top 10K prefixes. Fuzzy match optional second tier (ES).", "staff_plus_html": "Weekly rebuild = stale trending queries. Top-K only — no full corpus scan at keystroke. Privacy: aggregate logs, don't store raw PII queries. Example: Google Suggest — precomputed trie shards + aggressive CDN. Name metric + revisit trigger when they push depth.", "trade_html": "Weekly rebuild = stale trending queries. Top-K only — no full corpus scan at keystroke. Privacy: aggregate logs, don't store raw PII queries.", "example_html": "<em>Google Suggest — precomputed trie shards + aggressive CDN.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Writes & throughput", "slug": "writes-throughput", "severity": "pattern", "patterns": [{"title": "Scale writes past single DB", "slug": "scale-writes-past-single-db", "problem": "Write throughput exceeds what one database can handle — how do you scale writes?", "weak": "Shard later when Postgres is full.", "staff": "**Vertical scale** until pain is real, then **shard** by high-cardinality key (`user_id`, `tenant_id`). Alternative: **append-only** store (Cassandra, DynamoDB) for write-heavy access patterns. **Denormalize** — one physical table per query pattern (CQRS).", "staff_plus": "Sharding kills cross-shard JOINs and global transactions. Cassandra tuning (consistency level, compaction) is specialized. Premature sharding is ops nightmare. Example: Instagram shards media metadata by `user_id` when single PG master saturated. Name metric + revisit trigger when they push depth.", "trade": "Sharding kills cross-shard JOINs and global transactions. Cassandra tuning (consistency level, compaction) is specialized. Premature sharding is ops nightmare.", "example": "*Instagram shards media metadata by `user_id` when single PG master saturated.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "Write throughput exceeds what one database can handle — how do you scale writes?", "weak_html": "Shard later when Postgres is full.", "staff_html": "<strong>Vertical scale</strong> until pain is real, then <strong>shard</strong> by high-cardinality key (<code>user_id</code>, <code>tenant_id</code>). Alternative: <strong>append-only</strong> store (Cassandra, DynamoDB) for write-heavy access patterns. <strong>Denormalize</strong> — one physical table per query pattern (CQRS).", "staff_plus_html": "Sharding kills cross-shard JOINs and global transactions. Cassandra tuning (consistency level, compaction) is specialized. Premature sharding is ops nightmare. Example: Instagram shards media metadata by <code>user_id</code> when single PG master saturated. Name metric + revisit trigger when they push depth.", "trade_html": "Sharding kills cross-shard JOINs and global transactions. Cassandra tuning (consistency level, compaction) is specialized. Premature sharding is ops nightmare.", "example_html": "<em>Instagram shards media metadata by <code>user_id</code> when single PG master saturated.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "High write burst (flash sale)", "slug": "high-write-burst-flash-sale", "problem": "A flash sale creates a sudden 50× write spike — how do you handle it?", "weak": "Queue everyone in one mutex — fairness first.", "staff": "**Queue** purchase intents (Kafka/SQS). **Redis decr** or token bucket for inventory pre-check. **Single-row transaction** on PG for final commit. **Waitroom** / token at edge (Cloudflare Waiting Room) before API.", "staff_plus": "Queue adds seconds of latency to confirmation. Redis pre-check can oversell if not reconciled with DB — DB must be final arbiter. Example: Ticketmaster — virtual queue + Redis seat hold TTL + PG `SELECT FOR UPDATE`. Name metric + revisit trigger when they push depth.", "trade": "Queue adds seconds of latency to confirmation. Redis pre-check can oversell if not reconciled with DB — DB must be final arbiter.", "example": "*Ticketmaster — virtual queue + Redis seat hold TTL + PG `SELECT FOR UPDATE`.*", "visual": "[Seat hold 2-phase](interview-quick-fire.html#seat-hold)", "java_blocks": [], "severity": "high", "problem_html": "A flash sale creates a sudden 50× write spike — how do you handle it?", "weak_html": "Queue everyone in one mutex — fairness first.", "staff_html": "<strong>Queue</strong> purchase intents (Kafka/SQS). <strong>Redis decr</strong> or token bucket for inventory pre-check. <strong>Single-row transaction</strong> on PG for final commit. <strong>Waitroom</strong> / token at edge (Cloudflare Waiting Room) before API.", "staff_plus_html": "Queue adds seconds of latency to confirmation. Redis pre-check can oversell if not reconciled with DB — DB must be final arbiter. Example: Ticketmaster — virtual queue + Redis seat hold TTL + PG <code>SELECT FOR UPDATE</code>. Name metric + revisit trigger when they push depth.", "trade_html": "Queue adds seconds of latency to confirmation. Redis pre-check can oversell if not reconciled with DB — DB must be final arbiter.", "example_html": "<em>Ticketmaster — virtual queue + Redis seat hold TTL + PG <code>SELECT FOR UPDATE</code>.</em>", "visual_html": "<a href=\"#seat-hold\" class=\"diag-link\" data-diag=\"seat-hold\">Seat hold 2-phase</a>", "java_html": "", "java": ""}, {"title": "Idempotent writes", "slug": "idempotent-writes", "problem": "Network retries cause duplicate writes — how do you make writes idempotent?", "weak": "Check if row exists, then INSERT — good enough.", "staff": "Client sends **`Idempotency-Key`** (UUID). Server stores `(key → response)` in Redis/DB with 24h TTL. Duplicate request returns cached response without re-executing side effects.", "staff_plus": "Storage for keys. Key scope definition (per user vs global). Retries must send same key and body. Example: Stripe — same idempotency key on network retry never double-charges. Name metric + revisit trigger when they push depth.", "trade": "Storage for keys. Key scope definition (per user vs global). Retries must send same key and body.", "example": "*Stripe — same idempotency key on network retry never double-charges.*", "visual": "[Idempotency](interview-quick-fire.html#idempotency)", "java_blocks": [], "severity": "pattern", "problem_html": "Network retries cause duplicate writes — how do you make writes idempotent?", "weak_html": "Check if row exists, then INSERT — good enough.", "staff_html": "Client sends <strong><code>Idempotency-Key</code></strong> (UUID). Server stores <code>(key → response)</code> in Redis/DB with 24h TTL. Duplicate request returns cached response without re-executing side effects.", "staff_plus_html": "Storage for keys. Key scope definition (per user vs global). Retries must send same key and body. Example: Stripe — same idempotency key on network retry never double-charges. Name metric + revisit trigger when they push depth.", "trade_html": "Storage for keys. Key scope definition (per user vs global). Retries must send same key and body.", "example_html": "<em>Stripe — same idempotency key on network retry never double-charges.</em>", "visual_html": "<a href=\"#idempotency\" class=\"diag-link\" data-diag=\"idempotency\">Idempotency</a>", "java_html": "", "java": ""}, {"title": "Prevent double booking", "slug": "prevent-double-booking", "problem": "Two users book the last hotel room at the same time — how do you prevent double booking?", "weak": "SELECT then UPDATE in application code.", "staff": "**Pessimistic:** `SELECT FOR UPDATE` in transaction. **Optimistic:** version column `UPDATE ... WHERE version = ?`. Always **idempotency key** on client retries. Fail closed on conflict (409), never silent overwrite.", "staff_plus": "Pessimistic locks reduce concurrency (hot row serialization). Optimistic fails under high contention — need UX retry. Example: Airline seat map — row lock on `seat_id` for duration of checkout session. Name metric + revisit trigger when they push depth.", "trade": "Pessimistic locks reduce concurrency (hot row serialization). Optimistic fails under high contention — need UX retry.", "example": "*Airline seat map — row lock on `seat_id` for duration of checkout session.*", "visual": "[Seat hold 2-phase](interview-quick-fire.html#seat-hold)", "java_blocks": [], "severity": "high", "problem_html": "Two users book the last hotel room at the same time — how do you prevent double booking?", "weak_html": "SELECT then UPDATE in application code.", "staff_html": "<strong>Pessimistic:</strong> <code>SELECT FOR UPDATE</code> in transaction. <strong>Optimistic:</strong> version column <code>UPDATE ... WHERE version = ?</code>. Always <strong>idempotency key</strong> on client retries. Fail closed on conflict (409), never silent overwrite.", "staff_plus_html": "Pessimistic locks reduce concurrency (hot row serialization). Optimistic fails under high contention — need UX retry. Example: Airline seat map — row lock on <code>seat_id</code> for duration of checkout session. Name metric + revisit trigger when they push depth.", "trade_html": "Pessimistic locks reduce concurrency (hot row serialization). Optimistic fails under high contention — need UX retry.", "example_html": "<em>Airline seat map — row lock on <code>seat_id</code> for duration of checkout session.</em>", "visual_html": "<a href=\"#seat-hold\" class=\"diag-link\" data-diag=\"seat-hold\">Seat hold 2-phase</a>", "java_html": "", "java": ""}, {"title": "Write contention (multi-seat reservation)", "slug": "write-contention-multi-seat-reservation", "problem": "80,000 seats, 300K users hit Reserve at once — two fans book overlapping seats and you see `ERROR: deadlock detected`. How do you prevent double-booking and deadlocks at the database layer?", "weak": "Wrap read-check-update in `@Transactional` and assume the transaction isolates you. Under PostgreSQL **READ COMMITTED**, each statement gets its own snapshot — User A and B both `SELECT` seats 102–103 as available, then both `UPDATE`. Atomic commit, **double-booked rows**. `transaction` = atomicity, not row isolation.", "staff": "**Hot path (multi-seat, all-or-nothing):** sort seat IDs, then `SELECT … ORDER BY id FOR NO KEY UPDATE` (PostgreSQL) inside one transaction. Validate every seat is `available`, batch `UPDATE`, commit — lock hold under ~10ms. **Why sort?** Without `ORDER BY id`, overlapping reservations acquire row locks in heap-dependent order → circular wait → deadlock after `deadlock_timeout` (~1s). **Why NO KEY UPDATE?** We only change `status` / `held_by`, not key columns — avoids blocking FK `INSERT`s on child booking rows. **Alternatives:** single-row `UPDATE … WHERE status='available'` (fastest, one seat); optimistic `version` column (`UPDATE … WHERE id=? AND version=?`, retry on 0 rows); **SERIALIZABLE** for aggregate limits (max 6 seats/user) but needs app-wide adoption + retry on serialization failure. **Never** call payment APIs inside the lock window. Two-phase: **reserve** (10-min TTL) → pay → **confirm** with separate pessimistic lock on *your* held seats. Background sweeper releases expired holds (partial index on `held_until WHERE status='reserved'`).", "staff_plus": "Pessimistic locks serialize hot rows — 499 users wait if 500 want the same section. Optimistic fails fast but UX retries spike under Beyoncé-on-sale load. REPEATABLE READ stops lost updates on the *same* row but not write skew on disjoint seats for per-user caps. Rate-limit before DB (Redis token bucket), reads from replica for seat map, PgBouncer transaction pooling (~500 conns). Metrics: `reservation_conflict_rate`, `deadlock_count`, `lock_wait_p99`. Inspired by [Alina Kovtun — seat reservation, deadlocks & isolation levels](https://medium.com/womenintechnology/building-a-seat-reservation-system-deadlock-avoidance-and-transaction-isolation-levels-cad7186eb589). Name metric + revisit trigger when they push depth.", "trade": "Pessimistic = correct + simple but caps throughput on contested rows. Optimistic / conditional UPDATE = higher throughput, worse UX under contention. SERIALIZABLE = strongest invariants, mandatory retries + false-positive aborts. Ordered locking is non-negotiable for multi-row claims.", "example": "*Concert on-sale: User A wants [101,102,103], User B wants [102,103,104]. Unordered `FOR UPDATE` deadlocks in prod after first VACUUM; `ORDER BY id` + `FOR NO KEY UPDATE` serializes safely. Reject with 409 beats double-sell.*", "visual": "[Seat hold 2-phase](interview-quick-fire.html#seat-hold)", "java_blocks": [{"title": "Broken — read-check-write gap under READ COMMITTED", "code": "@Transactional\npublic void reserveBroken(List<Long> seatIds, long userId) {\n List<Seat> seats = seatRepo.findAllById(seatIds);\n if (seats.stream().anyMatch(s -> !\"available\".equals(s.getStatus()))) {\n throw new SeatsNotAvailableException();\n }\n seats.forEach(s -> {\n s.setStatus(\"reserved\");\n s.setHeldBy(userId);\n s.setHeldUntil(Instant.now().plus(Duration.ofMinutes(10)));\n });\n seatRepo.saveAll(seats); // both TXs may commit overlapping seats\n}"}, {"title": "Production — ordered pessimistic lock, all-or-nothing (Spring JDBC)", "code": "@Transactional\npublic ReservationResponse reserve(List<Long> seatIds, long userId) {\n List<Long> sortedIds = seatIds.stream().distinct().sorted().toList();\n if (sortedIds.isEmpty() || sortedIds.size() > 6) {\n throw new IllegalArgumentException(\"Select 1–6 seats\");\n }\n\n String lockSql = \"\"\"\n SELECT id, status FROM seats\n WHERE id = ANY (?)\n ORDER BY id\n FOR NO KEY UPDATE\n \"\"\";\n\n List<Seat> locked = jdbc.query(lockSql,\n ps -> ps.setArray(1, ps.getConnection()\n .createArrayOf(\"bigint\", sortedIds.toArray(Long[]::new))),\n seatRowMapper);\n\n if (locked.size() != sortedIds.size()) {\n throw new SeatsNotFoundException(sortedIds);\n }\n List<Long> taken = locked.stream()\n .filter(s -> !\"available\".equals(s.getStatus()))\n .map(Seat::getId)\n .toList();\n if (!taken.isEmpty()) {\n throw new SeatsNotAvailableException(taken);\n }\n\n Instant expiresAt = Instant.now().plus(Duration.ofMinutes(10));\n String updateSql = \"\"\"\n UPDATE seats\n SET status = 'reserved', held_by = ?, held_until = ?, version = version + 1\n WHERE id = ANY (?) AND status = 'available'\n \"\"\";\n\n int updated = jdbc.update(updateSql,\n userId, Timestamp.from(expiresAt), sortedIds.toArray(Long[]::new));\n if (updated != sortedIds.size()) {\n throw new ConcurrentModificationException(\"Seat race during update\");\n }\n return new ReservationResponse(sortedIds, userId, expiresAt);\n}"}, {"title": "Single-seat fast path — one atomic UPDATE, no explicit transaction", "code": "public boolean claimSeat(long seatId, long userId) {\n int n = jdbc.update(\"\"\"\n UPDATE seats\n SET status = 'reserved',\n held_by = ?,\n held_until = now() + interval '10 minutes'\n WHERE id = ? AND status = 'available'\n \"\"\", userId, seatId);\n return n == 1;\n}"}], "severity": "high", "problem_html": "80,000 seats, 300K users hit Reserve at once — two fans book overlapping seats and you see <code>ERROR: deadlock detected</code>. How do you prevent double-booking and deadlocks at the database layer?", "weak_html": "Wrap read-check-update in <code>@Transactional</code> and assume the transaction isolates you. Under PostgreSQL <strong>READ COMMITTED</strong>, each statement gets its own snapshot — User A and B both <code>SELECT</code> seats 102–103 as available, then both <code>UPDATE</code>. Atomic commit, <strong>double-booked rows</strong>. <code>transaction</code> = atomicity, not row isolation.", "staff_html": "<strong>Hot path (multi-seat, all-or-nothing):</strong> sort seat IDs, then <code>SELECT … ORDER BY id FOR NO KEY UPDATE</code> (PostgreSQL) inside one transaction. Validate every seat is <code>available</code>, batch <code>UPDATE</code>, commit — lock hold under ~10ms. <strong>Why sort?</strong> Without <code>ORDER BY id</code>, overlapping reservations acquire row locks in heap-dependent order → circular wait → deadlock after <code>deadlock_timeout</code> (~1s). <strong>Why NO KEY UPDATE?</strong> We only change <code>status</code> / <code>held_by</code>, not key columns — avoids blocking FK <code>INSERT</code>s on child booking rows. <strong>Alternatives:</strong> single-row <code>UPDATE … WHERE status='available'</code> (fastest, one seat); optimistic <code>version</code> column (<code>UPDATE … WHERE id=? AND version=?</code>, retry on 0 rows); <strong>SERIALIZABLE</strong> for aggregate limits (max 6 seats/user) but needs app-wide adoption + retry on serialization failure. <strong>Never</strong> call payment APIs inside the lock window. Two-phase: <strong>reserve</strong> (10-min TTL) → pay → <strong>confirm</strong> with separate pessimistic lock on <em>your</em> held seats. Background sweeper releases expired holds (partial index on <code>held_until WHERE status='reserved'</code>).", "staff_plus_html": "Pessimistic locks serialize hot rows — 499 users wait if 500 want the same section. Optimistic fails fast but UX retries spike under Beyoncé-on-sale load. REPEATABLE READ stops lost updates on the <em>same</em> row but not write skew on disjoint seats for per-user caps. Rate-limit before DB (Redis token bucket), reads from replica for seat map, PgBouncer transaction pooling (~500 conns). Metrics: <code>reservation_conflict_rate</code>, <code>deadlock_count</code>, <code>lock_wait_p99</code>. Inspired by <a href=\"https://medium.com/womenintechnology/building-a-seat-reservation-system-deadlock-avoidance-and-transaction-isolation-levels-cad7186eb589\">Alina Kovtun — seat reservation, deadlocks & isolation levels</a>. Name metric + revisit trigger when they push depth.", "trade_html": "Pessimistic = correct + simple but caps throughput on contested rows. Optimistic / conditional UPDATE = higher throughput, worse UX under contention. SERIALIZABLE = strongest invariants, mandatory retries + false-positive aborts. Ordered locking is non-negotiable for multi-row claims.", "example_html": "<em>Concert on-sale: User A wants [101,102,103], User B wants [102,103,104]. Unordered <code>FOR UPDATE</code> deadlocks in prod after first VACUUM; <code>ORDER BY id</code> + <code>FOR NO KEY UPDATE</code> serializes safely. Reject with 409 beats double-sell.</em>", "visual_html": "<a href=\"#seat-hold\" class=\"diag-link\" data-diag=\"seat-hold\">Seat hold 2-phase</a>", "java_html": "<div class=\"qf-java-wrap\"><div class=\"qf-java-label\">Broken — read-check-write gap under READ COMMITTED</div><pre class=\"qf-java\"><code>@Transactional\npublic void reserveBroken(List<Long> seatIds, long userId) {\n List<Seat> seats = seatRepo.findAllById(seatIds);\n if (seats.stream().anyMatch(s -> !"available".equals(s.getStatus()))) {\n throw new SeatsNotAvailableException();\n }\n seats.forEach(s -> {\n s.setStatus("reserved");\n s.setHeldBy(userId);\n s.setHeldUntil(Instant.now().plus(Duration.ofMinutes(10)));\n });\n seatRepo.saveAll(seats); // both TXs may commit overlapping seats\n}</code></pre><div class=\"qf-java-label\">Production — ordered pessimistic lock, all-or-nothing (Spring JDBC)</div><pre class=\"qf-java\"><code>@Transactional\npublic ReservationResponse reserve(List<Long> seatIds, long userId) {\n List<Long> sortedIds = seatIds.stream().distinct().sorted().toList();\n if (sortedIds.isEmpty() || sortedIds.size() > 6) {\n throw new IllegalArgumentException("Select 1–6 seats");\n }\n\n String lockSql = """\n SELECT id, status FROM seats\n WHERE id = ANY (?)\n ORDER BY id\n FOR NO KEY UPDATE\n """;\n\n List<Seat> locked = jdbc.query(lockSql,\n ps -> ps.setArray(1, ps.getConnection()\n .createArrayOf("bigint", sortedIds.toArray(Long[]::new))),\n seatRowMapper);\n\n if (locked.size() != sortedIds.size()) {\n throw new SeatsNotFoundException(sortedIds);\n }\n List<Long> taken = locked.stream()\n .filter(s -> !"available".equals(s.getStatus()))\n .map(Seat::getId)\n .toList();\n if (!taken.isEmpty()) {\n throw new SeatsNotAvailableException(taken);\n }\n\n Instant expiresAt = Instant.now().plus(Duration.ofMinutes(10));\n String updateSql = """\n UPDATE seats\n SET status = 'reserved', held_by = ?, held_until = ?, version = version + 1\n WHERE id = ANY (?) AND status = 'available'\n """;\n\n int updated = jdbc.update(updateSql,\n userId, Timestamp.from(expiresAt), sortedIds.toArray(Long[]::new));\n if (updated != sortedIds.size()) {\n throw new ConcurrentModificationException("Seat race during update");\n }\n return new ReservationResponse(sortedIds, userId, expiresAt);\n}</code></pre><div class=\"qf-java-label\">Single-seat fast path — one atomic UPDATE, no explicit transaction</div><pre class=\"qf-java\"><code>public boolean claimSeat(long seatId, long userId) {\n int n = jdbc.update("""\n UPDATE seats\n SET status = 'reserved',\n held_by = ?,\n held_until = now() + interval '10 minutes'\n WHERE id = ? AND status = 'available'\n """, userId, seatId);\n return n == 1;\n}</code></pre></div>", "java": "@Transactional\npublic void reserveBroken(List<Long> seatIds, long userId) {\n List<Seat> seats = seatRepo.findAllById(seatIds);\n if (seats.stream().anyMatch(s -> !\"available\".equals(s.getStatus()))) {\n throw new SeatsNotAvailableException();\n }\n seats.forEach(s -> {\n s.setStatus(\"reserved\");\n s.setHeldBy(userId);\n s.setHeldUntil(Instant.now().plus(Duration.ofMinutes(10)));\n });\n seatRepo.saveAll(seats); // both TXs may commit overlapping seats\n}\n@Transactional\npublic ReservationResponse reserve(List<Long> seatIds, long userId) {\n List<Long> sortedIds = seatIds.stream().distinct().sorted().toList();\n if (sortedIds.isEmpty() || sortedIds.size() > 6) {\n throw new IllegalArgumentException(\"Select 1–6 seats\");\n }\n\n String lockSql = \"\"\"\n SELECT id, status FROM seats\n WHERE id = ANY (?)\n ORDER BY id\n FOR NO KEY UPDATE\n \"\"\";\n\n List<Seat> locked = jdbc.query(lockSql,\n ps -> ps.setArray(1, ps.getConnection()\n .createArrayOf(\"bigint\", sortedIds.toArray(Long[]::new))),\n seatRowMapper);\n\n if (locked.size() != sortedIds.size()) {\n throw new SeatsNotFoundException(sortedIds);\n }\n List<Long> taken = locked.stream()\n .filter(s -> !\"available\".equals(s.getStatus()))\n .map(Seat::getId)\n .toList();\n if (!taken.isEmpty()) {\n throw new SeatsNotAvailableException(taken);\n }\n\n Instant expiresAt = Instant.now().plus(Duration.ofMinutes(10));\n String updateSql = \"\"\"\n UPDATE seats\n SET status = 'reserved', held_by = ?, held_until = ?, version = version + 1\n WHERE id = ANY (?) AND status = 'available'\n \"\"\";\n\n int updated = jdbc.update(updateSql,\n userId, Timestamp.from(expiresAt), sortedIds.toArray(Long[]::new));\n if (updated != sortedIds.size()) {\n throw new ConcurrentModificationException(\"Seat race during update\");\n }\n return new ReservationResponse(sortedIds, userId, expiresAt);\n}\npublic boolean claimSeat(long seatId, long userId) {\n int n = jdbc.update(\"\"\"\n UPDATE seats\n SET status = 'reserved',\n held_by = ?,\n held_until = now() + interval '10 minutes'\n WHERE id = ? AND status = 'available'\n \"\"\", userId, seatId);\n return n == 1;\n}"}, {"title": "Distributed counter", "slug": "distributed-counter", "problem": "You need a globally accurate view count across millions of servers — how do you implement it?", "weak": "INCR one global Redis key for all traffic.", "staff": "**Redis INCR** for real-time; **batch flush** to DB every N seconds. Or **pre-allocated ranges** per server (Snowflake-style). Never `read → add → write` in app without CAS.", "staff_plus": "Flush window loses counts on Redis failure unless AOF enabled. Range allocation can leave gaps on crash. Example: YouTube view counter — approximate counts OK; HyperLogLog or batched increments. Name metric + revisit trigger when they push depth.", "trade": "Flush window loses counts on Redis failure unless AOF enabled. Range allocation can leave gaps on crash.", "example": "*YouTube view counter — approximate counts OK; HyperLogLog or batched increments.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "You need a globally accurate view count across millions of servers — how do you implement it?", "weak_html": "INCR one global Redis key for all traffic.", "staff_html": "<strong>Redis INCR</strong> for real-time; <strong>batch flush</strong> to DB every N seconds. Or <strong>pre-allocated ranges</strong> per server (Snowflake-style). Never <code>read → add → write</code> in app without CAS.", "staff_plus_html": "Flush window loses counts on Redis failure unless AOF enabled. Range allocation can leave gaps on crash. Example: YouTube view counter — approximate counts OK; HyperLogLog or batched increments. Name metric + revisit trigger when they push depth.", "trade_html": "Flush window loses counts on Redis failure unless AOF enabled. Range allocation can leave gaps on crash.", "example_html": "<em>YouTube view counter — approximate counts OK; HyperLogLog or batched increments.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Unique ID at scale", "slug": "unique-id-at-scale", "problem": "You need unique IDs at 10,000 per millisecond — what approach do you use?", "weak": "UUID v4 everywhere — collisions are negligible.", "staff": "**Snowflake** (time + machine + sequence) for sortable 64-bit IDs. **UUID v7** for distributed without coordination. **DB sequence** with `hi/lo` allocation per app instance for simplicity.", "staff_plus": "Snowflake needs clock sync and machine ID registry. UUIDs aren't human-friendly. Sequential IDs leak growth rate. Example: Twitter Snowflake — roughly time-ordered tweets without central DB. Name metric + revisit trigger when they push depth.", "trade": "Snowflake needs clock sync and machine ID registry. UUIDs aren't human-friendly. Sequential IDs leak growth rate.", "example": "*Twitter Snowflake — roughly time-ordered tweets without central DB.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "You need unique IDs at 10,000 per millisecond — what approach do you use?", "weak_html": "UUID v4 everywhere — collisions are negligible.", "staff_html": "<strong>Snowflake</strong> (time + machine + sequence) for sortable 64-bit IDs. <strong>UUID v7</strong> for distributed without coordination. <strong>DB sequence</strong> with <code>hi/lo</code> allocation per app instance for simplicity.", "staff_plus_html": "Snowflake needs clock sync and machine ID registry. UUIDs aren't human-friendly. Sequential IDs leak growth rate. Example: Twitter Snowflake — roughly time-ordered tweets without central DB. Name metric + revisit trigger when they push depth.", "trade_html": "Snowflake needs clock sync and machine ID registry. UUIDs aren't human-friendly. Sequential IDs leak growth rate.", "example_html": "<em>Twitter Snowflake — roughly time-ordered tweets without central DB.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Consistency & correctness", "slug": "consistency-correctness", "severity": "important", "patterns": [{"title": "Strong vs eventual consistency", "slug": "strong-vs-eventual-consistency", "problem": "When would you choose strong consistency versus eventual consistency?", "weak": "Always use strong consistency — users hate stale data.", "staff": "Draw a line: **strong (ACID)** where invariants matter (money, inventory, seat). **Eventual** for search index, analytics, activity feeds. Say aloud: *\"This path is AP; users may see 2s lag.\"*", "staff_plus": "Strong limits throughput and complicates geo distribution. Eventual needs UX that tolerates staleness or self-corrects. Example: Bank transfer — PG transaction. Instagram like count — eventual + periodic reconcile. Name metric + revisit trigger when they push depth.", "trade": "Strong limits throughput and complicates geo distribution. Eventual needs UX that tolerates staleness or self-corrects.", "example": "*Bank transfer — PG transaction. Instagram like count — eventual + periodic reconcile.*", "visual": "", "java_blocks": [], "severity": "important", "problem_html": "When would you choose strong consistency versus eventual consistency?", "weak_html": "Always use strong consistency — users hate stale data.", "staff_html": "Draw a line: <strong>strong (ACID)</strong> where invariants matter (money, inventory, seat). <strong>Eventual</strong> for search index, analytics, activity feeds. Say aloud: <em>"This path is AP; users may see 2s lag."</em>", "staff_plus_html": "Strong limits throughput and complicates geo distribution. Eventual needs UX that tolerates staleness or self-corrects. Example: Bank transfer — PG transaction. Instagram like count — eventual + periodic reconcile. Name metric + revisit trigger when they push depth.", "trade_html": "Strong limits throughput and complicates geo distribution. Eventual needs UX that tolerates staleness or self-corrects.", "example_html": "<em>Bank transfer — PG transaction. Instagram like count — eventual + periodic reconcile.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Guarantee exactly-once", "slug": "guarantee-exactly-once", "problem": "How do you guarantee exactly-once processing in a distributed pipeline?", "weak": "Kafka exactly-once semantics solve it end-to-end.", "staff": "True exactly-once needs **distributed transactions (2PC)** or **Kafka transactions** — expensive and fragile. Default: **at-least-once delivery + idempotent consumer** + dedup store. Document: *\"Duplicates possible but harmless.\"*", "staff_plus": "Idempotency design burden on every handler. 2PC blocks on coordinator failure. Example: Payment webhook — store `event_id` before crediting wallet. Name metric + revisit trigger when they push depth.", "trade": "Idempotency design burden on every handler. 2PC blocks on coordinator failure.", "example": "*Payment webhook — store `event_id` before crediting wallet.*", "visual": "", "java_blocks": [], "severity": "important", "problem_html": "How do you guarantee exactly-once processing in a distributed pipeline?", "weak_html": "Kafka exactly-once semantics solve it end-to-end.", "staff_html": "True exactly-once needs <strong>distributed transactions (2PC)</strong> or <strong>Kafka transactions</strong> — expensive and fragile. Default: <strong>at-least-once delivery + idempotent consumer</strong> + dedup store. Document: <em>"Duplicates possible but harmless."</em>", "staff_plus_html": "Idempotency design burden on every handler. 2PC blocks on coordinator failure. Example: Payment webhook — store <code>event_id</code> before crediting wallet. Name metric + revisit trigger when they push depth.", "trade_html": "Idempotency design burden on every handler. 2PC blocks on coordinator failure.", "example_html": "<em>Payment webhook — store <code>event_id</code> before crediting wallet.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Cross-service transaction", "slug": "cross-service-transaction", "problem": "Payment requires debiting one service and crediting another — how do you handle the transaction?", "weak": "Two-phase commit across all microservices.", "staff": "Avoid 2PC across microservices. Use **saga**: local TX + event; on downstream failure run **compensating transaction** (refund, cancel hold). **Outbox pattern** ensures event published iff local commit.", "staff_plus": "Sagas are eventually consistent — intermediate states visible. Compensation logic is easy to get wrong (need idempotent compensations). Example: Travel booking — reserve flight → reserve hotel; if hotel fails, saga publishes cancel-flight. Name metric + revisit trigger when they push depth.", "trade": "Sagas are eventually consistent — intermediate states visible. Compensation logic is easy to get wrong (need idempotent compensations).", "example": "*Travel booking — reserve flight → reserve hotel; if hotel fails, saga publishes cancel-flight.*", "visual": "[Saga](interview-quick-fire.html#saga)", "java_blocks": [], "severity": "important", "problem_html": "Payment requires debiting one service and crediting another — how do you handle the transaction?", "weak_html": "Two-phase commit across all microservices.", "staff_html": "Avoid 2PC across microservices. Use <strong>saga</strong>: local TX + event; on downstream failure run <strong>compensating transaction</strong> (refund, cancel hold). <strong>Outbox pattern</strong> ensures event published iff local commit.", "staff_plus_html": "Sagas are eventually consistent — intermediate states visible. Compensation logic is easy to get wrong (need idempotent compensations). Example: Travel booking — reserve flight → reserve hotel; if hotel fails, saga publishes cancel-flight. Name metric + revisit trigger when they push depth.", "trade_html": "Sagas are eventually consistent — intermediate states visible. Compensation logic is easy to get wrong (need idempotent compensations).", "example_html": "<em>Travel booking — reserve flight → reserve hotel; if hotel fails, saga publishes cancel-flight.</em>", "visual_html": "<a href=\"#saga\" class=\"diag-link\" data-diag=\"saga\">Saga</a>", "java_html": "", "java": ""}, {"title": "Read-your-writes", "slug": "read-your-writes", "problem": "After a user posts, their feed does not show it — how do you guarantee read-your-writes?", "weak": "Sticky sessions to any random replica.", "staff": "After write, route that user's reads to **primary** or **sticky session** to leader for N seconds. Or return **updated entity in write response** so client doesn't need immediate re-read.", "staff_plus": "Primary reads reduce replica utility. Stickiness complicates load balancing. Example: Post tweet — API returns tweet object; timeline refresh uses primary for 3s. Name metric + revisit trigger when they push depth.", "trade": "Primary reads reduce replica utility. Stickiness complicates load balancing.", "example": "*Post tweet — API returns tweet object; timeline refresh uses primary for 3s.*", "visual": "[Replica lag](interview-quick-fire.html#replica-lag)", "java_blocks": [], "severity": "important", "problem_html": "After a user posts, their feed does not show it — how do you guarantee read-your-writes?", "weak_html": "Sticky sessions to any random replica.", "staff_html": "After write, route that user's reads to <strong>primary</strong> or <strong>sticky session</strong> to leader for N seconds. Or return <strong>updated entity in write response</strong> so client doesn't need immediate re-read.", "staff_plus_html": "Primary reads reduce replica utility. Stickiness complicates load balancing. Example: Post tweet — API returns tweet object; timeline refresh uses primary for 3s. Name metric + revisit trigger when they push depth.", "trade_html": "Primary reads reduce replica utility. Stickiness complicates load balancing.", "example_html": "<em>Post tweet — API returns tweet object; timeline refresh uses primary for 3s.</em>", "visual_html": "<a href=\"#replica-lag\" class=\"diag-link\" data-diag=\"replica-lag\">Replica lag</a>", "java_html": "", "java": ""}]}, {"title": "Money & transactions", "slug": "money-transactions", "severity": "important", "patterns": [{"title": "Payment correctness", "slug": "payment-correctness", "problem": "A payment timeout causes a client retry — how do you prevent double charging?", "weak": "Charge the card; if timeout, retry the charge.", "staff": "**Double-entry ledger** (debits = credits). **Idempotency key** per payment attempt. **Never assume timeout = failure** — query PSP with same key before retry. **Immutable event log**.", "staff_plus": "Ledger storage grows forever — archive policy. Reconciliation jobs add ops. Strong consistency limits TPS per shard. Example: Stripe — PaymentIntent state machine + idempotent API. Name metric + revisit trigger when they push depth.", "trade": "Ledger storage grows forever — archive policy. Reconciliation jobs add ops. Strong consistency limits TPS per shard.", "example": "*Stripe — PaymentIntent state machine + idempotent API.*", "visual": "[Idempotency](interview-quick-fire.html#idempotency) · [Saga](interview-quick-fire.html#saga)", "java_blocks": [], "severity": "critical", "problem_html": "A payment timeout causes a client retry — how do you prevent double charging?", "weak_html": "Charge the card; if timeout, retry the charge.", "staff_html": "<strong>Double-entry ledger</strong> (debits = credits). <strong>Idempotency key</strong> per payment attempt. <strong>Never assume timeout = failure</strong> — query PSP with same key before retry. <strong>Immutable event log</strong>.", "staff_plus_html": "Ledger storage grows forever — archive policy. Reconciliation jobs add ops. Strong consistency limits TPS per shard. Example: Stripe — PaymentIntent state machine + idempotent API. Name metric + revisit trigger when they push depth.", "trade_html": "Ledger storage grows forever — archive policy. Reconciliation jobs add ops. Strong consistency limits TPS per shard.", "example_html": "<em>Stripe — PaymentIntent state machine + idempotent API.</em>", "visual_html": "<a href=\"#idempotency\" class=\"diag-link\" data-diag=\"idempotency\">Idempotency</a> · <a href=\"#saga\" class=\"diag-link\" data-diag=\"saga\">Saga</a>", "java_html": "", "java": ""}, {"title": "Inventory / wallet balance", "slug": "inventory-wallet-balance", "problem": "How do you keep inventory or wallet balances correct under concurrent updates?", "weak": "UPDATE balance = balance - amount — SQL is atomic.", "staff": "**Single-row transaction:** `UPDATE inventory SET qty = qty - 1 WHERE id = ? AND qty > 0`. **Available balance** = settled − holds − pending. No cross-request RMW without lock.", "staff_plus": "Row-level locking caps QPS on hot SKU. Holds expire — need TTL job to release. Example: Airline — seat row locked for 15 min during checkout. Name metric + revisit trigger when they push depth.", "trade": "Row-level locking caps QPS on hot SKU. Holds expire — need TTL job to release.", "example": "*Airline — seat row locked for 15 min during checkout.*", "visual": "[Seat hold 2-phase](interview-quick-fire.html#seat-hold)", "java_blocks": [], "severity": "critical", "problem_html": "How do you keep inventory or wallet balances correct under concurrent updates?", "weak_html": "UPDATE balance = balance - amount — SQL is atomic.", "staff_html": "<strong>Single-row transaction:</strong> <code>UPDATE inventory SET qty = qty - 1 WHERE id = ? AND qty > 0</code>. <strong>Available balance</strong> = settled − holds − pending. No cross-request RMW without lock.", "staff_plus_html": "Row-level locking caps QPS on hot SKU. Holds expire — need TTL job to release. Example: Airline — seat row locked for 15 min during checkout. Name metric + revisit trigger when they push depth.", "trade_html": "Row-level locking caps QPS on hot SKU. Holds expire — need TTL job to release.", "example_html": "<em>Airline — seat row locked for 15 min during checkout.</em>", "visual_html": "<a href=\"#seat-hold\" class=\"diag-link\" data-diag=\"seat-hold\">Seat hold 2-phase</a>", "java_html": "", "java": ""}]}, {"title": "Fan-out & real-time", "slug": "fan-out-real-time", "severity": "pattern", "patterns": [{"title": "Fan-out to millions of followers", "slug": "fan-out-to-millions-of-followers", "problem": "A user with 50M followers posts — how do you fan out to follower feeds?", "weak": "Push every post to every follower's feed on write.", "staff": "**Hybrid fan-out:** push (precompute timeline on write) for normal accounts; **pull** (assemble on read) for celebrities above threshold (e.g. 10K followers). **Kafka** for async fan-out workers; **Cassandra/Redis** for timeline storage.", "staff_plus": "Push wastes work for inactive followers. Pull makes celebrity read slow — cache materialized partial feeds. Example: Twitter — push for most; pull for Bieber-class accounts. Name metric + revisit trigger when they push depth.", "trade": "Push wastes work for inactive followers. Pull makes celebrity read slow — cache materialized partial feeds.", "example": "*Twitter — push for most; pull for Bieber-class accounts.*", "visual": "[Fan-out hybrid](interview-quick-fire.html#fan-out)", "java_blocks": [], "severity": "pattern", "problem_html": "A user with 50M followers posts — how do you fan out to follower feeds?", "weak_html": "Push every post to every follower's feed on write.", "staff_html": "<strong>Hybrid fan-out:</strong> push (precompute timeline on write) for normal accounts; <strong>pull</strong> (assemble on read) for celebrities above threshold (e.g. 10K followers). <strong>Kafka</strong> for async fan-out workers; <strong>Cassandra/Redis</strong> for timeline storage.", "staff_plus_html": "Push wastes work for inactive followers. Pull makes celebrity read slow — cache materialized partial feeds. Example: Twitter — push for most; pull for Bieber-class accounts. Name metric + revisit trigger when they push depth.", "trade_html": "Push wastes work for inactive followers. Pull makes celebrity read slow — cache materialized partial feeds.", "example_html": "<em>Twitter — push for most; pull for Bieber-class accounts.</em>", "visual_html": "<a href=\"#fan-out\" class=\"diag-link\" data-diag=\"fan-out\">Fan-out hybrid</a>", "java_html": "", "java": ""}, {"title": "WebSocket at scale", "slug": "websocket-at-scale", "problem": "How do you scale WebSocket connections to millions of concurrent users?", "weak": "One giant WebSocket server holds all connections.", "staff": "**Dedicated connection tier** scaled separately from API. **Sticky sessions** or **pub/sub bridge** (Redis/Kafka) so any server can push to user on any connection server. **Connection registry:** `user_id → server_id`.", "staff_plus": "Sticky sessions complicate deploys and imbalance load. Pub/sub adds latency vs local-only push. Example: Slack — channel-based pub/sub; co-locate busy channels where possible. Name metric + revisit trigger when they push depth.", "trade": "Sticky sessions complicate deploys and imbalance load. Pub/sub adds latency vs local-only push.", "example": "*Slack — channel-based pub/sub; co-locate busy channels where possible.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "How do you scale WebSocket connections to millions of concurrent users?", "weak_html": "One giant WebSocket server holds all connections.", "staff_html": "<strong>Dedicated connection tier</strong> scaled separately from API. <strong>Sticky sessions</strong> or <strong>pub/sub bridge</strong> (Redis/Kafka) so any server can push to user on any connection server. <strong>Connection registry:</strong> <code>user_id → server_id</code>.", "staff_plus_html": "Sticky sessions complicate deploys and imbalance load. Pub/sub adds latency vs local-only push. Example: Slack — channel-based pub/sub; co-locate busy channels where possible. Name metric + revisit trigger when they push depth.", "trade_html": "Sticky sessions complicate deploys and imbalance load. Pub/sub adds latency vs local-only push.", "example_html": "<em>Slack — channel-based pub/sub; co-locate busy channels where possible.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Push notifications at scale", "slug": "push-notifications-at-scale", "problem": "How do you deliver push notifications to 100M devices reliably?", "weak": "Loop over all device tokens and send synchronously.", "staff": "API validates → **dedup** (`SETNX event_id`) → **per-channel Kafka topics** → workers call APNs/FCM. **Stagger** viral fan-out over 60–120s. **Remove dead tokens** immediately on provider error.", "staff_plus": "At-least-once delivery — dedup mandatory. Provider rate limits cap throughput — queue depth monitoring critical. Example: Uber ride arrived — high-priority queue bypasses marketing rate cap. Name metric + revisit trigger when they push depth.", "trade": "At-least-once delivery — dedup mandatory. Provider rate limits cap throughput — queue depth monitoring critical.", "example": "*Uber ride arrived — high-priority queue bypasses marketing rate cap.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "How do you deliver push notifications to 100M devices reliably?", "weak_html": "Loop over all device tokens and send synchronously.", "staff_html": "API validates → <strong>dedup</strong> (<code>SETNX event_id</code>) → <strong>per-channel Kafka topics</strong> → workers call APNs/FCM. <strong>Stagger</strong> viral fan-out over 60–120s. <strong>Remove dead tokens</strong> immediately on provider error.", "staff_plus_html": "At-least-once delivery — dedup mandatory. Provider rate limits cap throughput — queue depth monitoring critical. Example: Uber ride arrived — high-priority queue bypasses marketing rate cap. Name metric + revisit trigger when they push depth.", "trade_html": "At-least-once delivery — dedup mandatory. Provider rate limits cap throughput — queue depth monitoring critical.", "example_html": "<em>Uber ride arrived — high-priority queue bypasses marketing rate cap.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Messaging & async", "slug": "messaging-async", "severity": "pattern", "patterns": [{"title": "Decouple services", "slug": "decouple-services", "problem": "Two services are tightly coupled and one outage takes down the other — how do you decouple them?", "weak": "REST sync call chain between every service.", "staff": "**Kafka/SQS** between producer and consumer. Producer writes message and returns; consumer scales on **lag**. **DLQ** for failures after N retries.", "staff_plus": "Eventually consistent — user waits for async completion. Message ordering only per partition/key. Example: Email send — API enqueues; worker pool sends via SES. Name metric + revisit trigger when they push depth.", "trade": "Eventually consistent — user waits for async completion. Message ordering only per partition/key.", "example": "*Email send — API enqueues; worker pool sends via SES.*", "visual": "[Poison message](interview-quick-fire.html#poison-message) *(queue + DLQ pattern)*", "java_blocks": [], "severity": "pattern", "problem_html": "Two services are tightly coupled and one outage takes down the other — how do you decouple them?", "weak_html": "REST sync call chain between every service.", "staff_html": "<strong>Kafka/SQS</strong> between producer and consumer. Producer writes message and returns; consumer scales on <strong>lag</strong>. <strong>DLQ</strong> for failures after N retries.", "staff_plus_html": "Eventually consistent — user waits for async completion. Message ordering only per partition/key. Example: Email send — API enqueues; worker pool sends via SES. Name metric + revisit trigger when they push depth.", "trade_html": "Eventually consistent — user waits for async completion. Message ordering only per partition/key.", "example_html": "<em>Email send — API enqueues; worker pool sends via SES.</em>", "visual_html": "<a href=\"#poison-message\" class=\"diag-link\" data-diag=\"poison-message\">Poison message</a> <em>(queue + DLQ pattern)</em>", "java_html": "", "java": ""}, {"title": "Webhook delivery", "slug": "webhook-delivery", "problem": "You must deliver webhooks to third parties with retries and idempotency — how do you design it?", "weak": "Fire-and-forget HTTP POST from the request path.", "staff": "**Outbox table** in same TX as state change. Worker polls outbox, POSTs to merchant URL, **exponential backoff**, **DLQ** + dashboard for manual replay. **HMAC signature** on payload.", "staff_plus": "Merchant endpoint down → backlog grows — need max retention and alerting. Replay requires idempotent merchant API. Example: Stripe webhooks — signing secret; retry up to 3 days. Name metric + revisit trigger when they push depth.", "trade": "Merchant endpoint down → backlog grows — need max retention and alerting. Replay requires idempotent merchant API.", "example": "*Stripe webhooks — signing secret; retry up to 3 days.*", "visual": "[Dual-write vs outbox](interview-quick-fire.html#dual-write)", "java_blocks": [], "severity": "pattern", "problem_html": "You must deliver webhooks to third parties with retries and idempotency — how do you design it?", "weak_html": "Fire-and-forget HTTP POST from the request path.", "staff_html": "<strong>Outbox table</strong> in same TX as state change. Worker polls outbox, POSTs to merchant URL, <strong>exponential backoff</strong>, <strong>DLQ</strong> + dashboard for manual replay. <strong>HMAC signature</strong> on payload.", "staff_plus_html": "Merchant endpoint down → backlog grows — need max retention and alerting. Replay requires idempotent merchant API. Example: Stripe webhooks — signing secret; retry up to 3 days. Name metric + revisit trigger when they push depth.", "trade_html": "Merchant endpoint down → backlog grows — need max retention and alerting. Replay requires idempotent merchant API.", "example_html": "<em>Stripe webhooks — signing secret; retry up to 3 days.</em>", "visual_html": "<a href=\"#dual-write\" class=\"diag-link\" data-diag=\"dual-write\">Dual-write vs outbox</a>", "java_html": "", "java": ""}]}, {"title": "Storage & media", "slug": "storage-media", "severity": "pattern", "patterns": [{"title": "Store large files", "slug": "store-large-files", "problem": "How do you store and serve large files (images, PDFs, backups) at scale?", "weak": "Multipart upload to S3 in one HTTP request.", "staff": "**S3/GCS** for bytes; **DB for metadata** only. **Pre-signed URLs** for direct client upload/download — bytes never through app servers. **CDN** for read path.", "staff_plus": "Presigned URL leakage = temporary exposure — short TTL. Multipart upload complexity. Listing large buckets is slow — index metadata in DB. Example: Dropbox — metadata service + direct S3 chunk upload. Name metric + revisit trigger when they push depth.", "trade": "Presigned URL leakage = temporary exposure — short TTL. Multipart upload complexity. Listing large buckets is slow — index metadata in DB.", "example": "*Dropbox — metadata service + direct S3 chunk upload.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "How do you store and serve large files (images, PDFs, backups) at scale?", "weak_html": "Multipart upload to S3 in one HTTP request.", "staff_html": "<strong>S3/GCS</strong> for bytes; <strong>DB for metadata</strong> only. <strong>Pre-signed URLs</strong> for direct client upload/download — bytes never through app servers. <strong>CDN</strong> for read path.", "staff_plus_html": "Presigned URL leakage = temporary exposure — short TTL. Multipart upload complexity. Listing large buckets is slow — index metadata in DB. Example: Dropbox — metadata service + direct S3 chunk upload. Name metric + revisit trigger when they push depth.", "trade_html": "Presigned URL leakage = temporary exposure — short TTL. Multipart upload complexity. Listing large buckets is slow — index metadata in DB.", "example_html": "<em>Dropbox — metadata service + direct S3 chunk upload.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Video streaming", "slug": "video-streaming", "problem": "Design video upload, transcoding, and streaming for YouTube-scale traffic.", "weak": "Serve the original 4K file — clients buffer.", "staff": "Upload → **transcode ladder** (360p–4K) → **HLS segments** in object storage → **CDN**. **ABR manifest** lets client switch bitrate. Metadata in PG; bytes never in SQL.", "staff_plus": "Transcode lag — publish before all bitrates ready (progressive). Storage multiplication per resolution. Example: YouTube — parallel transcode jobs; 360p available within seconds. Name metric + revisit trigger when they push depth.", "trade": "Transcode lag — publish before all bitrates ready (progressive). Storage multiplication per resolution.", "example": "*YouTube — parallel transcode jobs; 360p available within seconds.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "Design video upload, transcoding, and streaming for YouTube-scale traffic.", "weak_html": "Serve the original 4K file — clients buffer.", "staff_html": "Upload → <strong>transcode ladder</strong> (360p–4K) → <strong>HLS segments</strong> in object storage → <strong>CDN</strong>. <strong>ABR manifest</strong> lets client switch bitrate. Metadata in PG; bytes never in SQL.", "staff_plus_html": "Transcode lag — publish before all bitrates ready (progressive). Storage multiplication per resolution. Example: YouTube — parallel transcode jobs; 360p available within seconds. Name metric + revisit trigger when they push depth.", "trade_html": "Transcode lag — publish before all bitrates ready (progressive). Storage multiplication per resolution.", "example_html": "<em>YouTube — parallel transcode jobs; 360p available within seconds.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Security & abuse", "slug": "security-abuse", "severity": "high", "patterns": [{"title": "Rate limiting", "slug": "rate-limiting", "problem": "Design a rate limiter for your public API.", "weak": "Return 429 when count > 100 — no per-user fairness.", "staff": "**Token bucket** or sliding window in Redis per `(user_id | IP | API key)`. Return **429 + Retry-After**. **Edge rate limit** (CDN/WAF) before origin. Separate tiers for auth vs anonymous.", "staff_plus": "Redis failure — fail open (abuse risk) vs fail closed (outage). Shared NAT IPs punish corporate users. Example: GitHub API — `X-RateLimit-Remaining` headers. Name metric + revisit trigger when they push depth.", "trade": "Redis failure — fail open (abuse risk) vs fail closed (outage). Shared NAT IPs punish corporate users.", "example": "*GitHub API — `X-RateLimit-Remaining` headers.*", "visual": "", "java_blocks": [], "severity": "high", "problem_html": "Design a rate limiter for your public API.", "weak_html": "Return 429 when count > 100 — no per-user fairness.", "staff_html": "<strong>Token bucket</strong> or sliding window in Redis per <code>(user_id | IP | API key)</code>. Return <strong>429 + Retry-After</strong>. <strong>Edge rate limit</strong> (CDN/WAF) before origin. Separate tiers for auth vs anonymous.", "staff_plus_html": "Redis failure — fail open (abuse risk) vs fail closed (outage). Shared NAT IPs punish corporate users. Example: GitHub API — <code>X-RateLimit-Remaining</code> headers. Name metric + revisit trigger when they push depth.", "trade_html": "Redis failure — fail open (abuse risk) vs fail closed (outage). Shared NAT IPs punish corporate users.", "example_html": "<em>GitHub API — <code>X-RateLimit-Remaining</code> headers.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "DDoS / abuse", "slug": "ddos-abuse", "problem": "Your API is being abused or DDoS'd — how do you protect it?", "weak": "Block bad IPs in application code after they hit us.", "staff": "**CDN + WAF** absorb L3/L7. **Challenge** (JS/captcha) for suspicious ASNs. **Origin only accepts CDN IP ranges**. Anomaly detection on error rate and geographic spikes.", "staff_plus": "WAF false positives block legit users. CDN cost scales with attack size. Example: Cloudflare Under Attack mode — interactive challenge before origin. Name metric + revisit trigger when they push depth.", "trade": "WAF false positives block legit users. CDN cost scales with attack size.", "example": "*Cloudflare Under Attack mode — interactive challenge before origin.*", "visual": "", "java_blocks": [], "severity": "high", "problem_html": "Your API is being abused or DDoS'd — how do you protect it?", "weak_html": "Block bad IPs in application code after they hit us.", "staff_html": "<strong>CDN + WAF</strong> absorb L3/L7. <strong>Challenge</strong> (JS/captcha) for suspicious ASNs. <strong>Origin only accepts CDN IP ranges</strong>. Anomaly detection on error rate and geographic spikes.", "staff_plus_html": "WAF false positives block legit users. CDN cost scales with attack size. Example: Cloudflare Under Attack mode — interactive challenge before origin. Name metric + revisit trigger when they push depth.", "trade_html": "WAF false positives block legit users. CDN cost scales with attack size.", "example_html": "<em>Cloudflare Under Attack mode — interactive challenge before origin.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Geo & search", "slug": "geo-search", "severity": "pattern", "patterns": [{"title": "Nearby search (Yelp, Uber)", "slug": "nearby-search-yelp-uber", "problem": "Find all restaurants or drivers within 5km of a user — how do you implement nearby search?", "weak": "PostGIS radius query on every map pan.", "staff": "**Geohash prefix** or PostGIS `ST_DWithin` for coarse filter → **refine** with haversine on small candidate set. **Cache** results per `(lat,lng, radius)` cell. Moving objects: **Redis GEO** + periodic refresh.", "staff_plus": "Geohash edge cases — query neighbor cells. PostGIS on huge tables needs GiST index and connection pool tuning. Example: Uber — geohash grid + surge pricing per cell. Name metric + revisit trigger when they push depth.", "trade": "Geohash edge cases — query neighbor cells. PostGIS on huge tables needs GiST index and connection pool tuning.", "example": "*Uber — geohash grid + surge pricing per cell.*", "visual": "", "java_blocks": [], "severity": "pattern", "problem_html": "Find all restaurants or drivers within 5km of a user — how do you implement nearby search?", "weak_html": "PostGIS radius query on every map pan.", "staff_html": "<strong>Geohash prefix</strong> or PostGIS <code>ST_DWithin</code> for coarse filter → <strong>refine</strong> with haversine on small candidate set. <strong>Cache</strong> results per <code>(lat,lng, radius)</code> cell. Moving objects: <strong>Redis GEO</strong> + periodic refresh.", "staff_plus_html": "Geohash edge cases — query neighbor cells. PostGIS on huge tables needs GiST index and connection pool tuning. Example: Uber — geohash grid + surge pricing per cell. Name metric + revisit trigger when they push depth.", "trade_html": "Geohash edge cases — query neighbor cells. PostGIS on huge tables needs GiST index and connection pool tuning.", "example_html": "<em>Uber — geohash grid + surge pricing per cell.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Observability & ops", "slug": "observability-ops", "severity": "prep", "patterns": [{"title": "Debug production incidents", "slug": "debug-production-incidents", "problem": "Production is degraded and the cause is unclear — walk me through your incident response.", "weak": "SSH in and tail logs on one server.", "staff": "**`trace_id`** propagated through headers. **Structured JSON logs**. **Metrics:** latency histogram, error rate, saturation (CPU, pool, queue depth). **Distributed tracing** (Jaeger/Tempo) for cross-service causality.", "staff_plus": "High-cardinality labels explode metrics cost. Trace sampling misses rare bugs — tail-based sampling helps. Example: p99 spike — trace shows one shard ES query 2s; others 20ms. Name metric + revisit trigger when they push depth.", "trade": "High-cardinality labels explode metrics cost. Trace sampling misses rare bugs — tail-based sampling helps.", "example": "*p99 spike — trace shows one shard ES query 2s; others 20ms.*", "visual": "", "java_blocks": [], "severity": "prep", "problem_html": "Production is degraded and the cause is unclear — walk me through your incident response.", "weak_html": "SSH in and tail logs on one server.", "staff_html": "<strong><code>trace_id</code></strong> propagated through headers. <strong>Structured JSON logs</strong>. <strong>Metrics:</strong> latency histogram, error rate, saturation (CPU, pool, queue depth). <strong>Distributed tracing</strong> (Jaeger/Tempo) for cross-service causality.", "staff_plus_html": "High-cardinality labels explode metrics cost. Trace sampling misses rare bugs — tail-based sampling helps. Example: p99 spike — trace shows one shard ES query 2s; others 20ms. Name metric + revisit trigger when they push depth.", "trade_html": "High-cardinality labels explode metrics cost. Trace sampling misses rare bugs — tail-based sampling helps.", "example_html": "<em>p99 spike — trace shows one shard ES query 2s; others 20ms.</em>", "visual_html": "", "java_html": "", "java": ""}, {"title": "Cardinality explosion (metrics)", "slug": "cardinality-explosion-metrics", "problem": "Your metrics bill exploded because someone used user_id as a label — how do you prevent it?", "weak": "Tag every span with user_id for rich dashboards.", "staff": "**Label allowlists** per metric — no `user_id` on request latency. **Cap series** per metric; reject or aggregate high-cardinality labels. **Recording rules** for aggregates.", "staff_plus": "Less per-user debuggability in metrics — use traces/logs for that. Allowlist slows developer iteration. Example: Datadog bill 3× after someone tagged `user_id` on HTTP metric. Name metric + revisit trigger when they push depth.", "trade": "Less per-user debuggability in metrics — use traces/logs for that. Allowlist slows developer iteration.", "example": "*Datadog bill 3× after someone tagged `user_id` on HTTP metric.*", "visual": "", "java_blocks": [], "severity": "prep", "problem_html": "Your metrics bill exploded because someone used user_id as a label — how do you prevent it?", "weak_html": "Tag every span with user_id for rich dashboards.", "staff_html": "<strong>Label allowlists</strong> per metric — no <code>user_id</code> on request latency. <strong>Cap series</strong> per metric; reject or aggregate high-cardinality labels. <strong>Recording rules</strong> for aggregates.", "staff_plus_html": "Less per-user debuggability in metrics — use traces/logs for that. Allowlist slows developer iteration. Example: Datadog bill 3× after someone tagged <code>user_id</code> on HTTP metric. Name metric + revisit trigger when they push depth.", "trade_html": "Less per-user debuggability in metrics — use traces/logs for that. Allowlist slows developer iteration.", "example_html": "<em>Datadog bill 3× after someone tagged <code>user_id</code> on HTTP metric.</em>", "visual_html": "", "java_html": "", "java": ""}]}, {"title": "Practice drill", "slug": "practice-drill", "severity": "prep", "patterns": []}, {"title": "Answer template (use every time)", "slug": "answer-template-use-every-time", "severity": "prep", "patterns": []}, {"title": "How to go deeper — interview prep", "slug": "how-to-go-deeper-interview-prep", "severity": "prep", "patterns": []}, {"title": "Visual archetypes", "slug": "visual-archetypes", "severity": "prep", "patterns": []}];
const DIAGRAM_IDS = new Set(["cache-aside", "thundering-herd", "retry-storm", "hot-key", "split-brain", "poison-message", "n1-batch", "connection-pool", "replica-lag", "dual-write", "fan-out", "saga", "idempotency", "seat-hold", "straggler", "token-bucket", "websocket-scale"]);
let currentView = 'patterns';
function isDiagramHash(hash) {
const id = (hash || '').replace(/^#/, '');
return id === 'diagrams' || DIAGRAM_IDS.has(id);
}
function setView(view, opts = {}) {
currentView = view;
document.getElementById('view-patterns')?.classList.toggle('view-active', view === 'patterns');
document.getElementById('view-diagrams')?.classList.toggle('view-active', view === 'diagrams');
document.querySelectorAll('.view-tabs .vtab').forEach(b => {
b.classList.toggle('on', b.dataset.view === view);
});
const tools = document.getElementById('sb-patterns-tools');
if (tools) tools.style.display = view === 'patterns' ? '' : 'none';
if (view === 'diagrams' && typeof bootDiagrams === 'function') {
let diagId = opts.diagId;
if (diagId === 'diagrams') diagId = null;
if (!diagId && isDiagramHash(location.hash)) {
const h = location.hash.replace(/^#/, '');
diagId = h === 'diagrams' ? null : h;
}
bootDiagrams(diagId || null);
}
}
function routeHash() {
if (isDiagramHash(location.hash)) {
const id = location.hash.replace(/^#/, '');
setView('diagrams', { diagId: id });
return;
}
setView('patterns');
if (location.hash) {
setTimeout(() => {
const el = document.querySelector(location.hash);
if (el) {
el.scrollIntoView({ behavior: 'smooth' });
el.classList?.add('open');
}
}, 120);
}
}
document.querySelectorAll('.view-tabs .vtab').forEach(b => {
b.onclick = () => {
if (b.dataset.view === 'diagrams') {
location.hash = 'diagrams';
} else {
if (location.hash) history.replaceState(null, '', location.pathname + location.search);
setView('patterns');
}
};
});
document.addEventListener('click', e => {
const a = e.target.closest('a.diag-link');
if (!a) return;
e.preventDefault();
const id = a.dataset.diag || (a.getAttribute('href') || '').replace(/^#/, '');
if (id) location.hash = id;
});
window.addEventListener('hashchange', routeHash);
function render() {
const root = document.getElementById('root');
const sb = document.getElementById('sb-nav');
const q = (document.getElementById('q').value || '').toLowerCase();
const active = [...document.querySelectorAll('.fchip.on')].map(b => b.dataset.f);
const showAll = active.includes('all') || active.length === 0;
root.innerHTML = '';
sb.innerHTML = '';
DATA.forEach(sec => {
const patterns = sec.patterns.filter(p => {
if (!showAll && !active.includes(p.severity)) return false;
const hay = (p.title + ' ' + (p.problem||'') + ' ' + (p.weak||'') + ' ' + p.staff + ' ' + p.trade + ' ' + (p.java||'')).toLowerCase();
return !q || hay.includes(q);
});
if (!patterns.length) return;
const s = SEV[sec.severity] || SEV.prep;
const secEl = document.createElement('section');
secEl.className = 'sec';
secEl.id = sec.slug;
secEl.innerHTML = `<div class="sec-hdr ${sec.severity}">${s.emoji} ${sec.title}</div>`;
const sbSec = document.createElement('div');
sbSec.className = 'sb-group';
const secLink = document.createElement('a');
secLink.className = 'sb-sec-link';
secLink.href = '#' + sec.slug;
secLink.innerHTML = `<span>${s.emoji} ${sec.title}</span><span class="sb-count">${patterns.length}</span>`;
secLink.onclick = e => {
e.preventDefault();
document.getElementById(sec.slug)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
sbSec.appendChild(secLink);
patterns.forEach(p => {
const ps = SEV[p.severity] || SEV.pattern;
const card = document.createElement('div');
card.className = 'card';
card.id = p.slug;
card.innerHTML = `
<div class="card-hdr">
<span class="badge ${p.severity}">${ps.emoji} ${ps.label}</span>
<span class="card-title">${p.title}</span>
<span class="card-chev">▶</span>
</div>
<div class="card-body">
${p.problem_html ? `<div class="callout problem"><strong>💬 Problem</strong>${p.problem_html}</div>` : ''}
${p.weak_html ? `<div class="callout critical"><strong>🔴 Weak</strong>${p.weak_html}</div>` : ''}
<div class="callout ${p.severity}"><strong>🟡 Strong</strong>${p.staff_html}</div>
${p.staff_plus_html ? `<div class="callout pattern"><strong>🟢 Staff+</strong>${p.staff_plus_html}</div>` : ''}
<div class="callout ${p.severity}" style="opacity:.92"><strong>Trade-offs</strong>${p.trade_html}</div>
<div class="callout ${p.severity}" style="opacity:.85"><strong>Example</strong>${p.example_html}${p.java_html ? p.java_html : ''}</div>
${p.visual_html ? `<div class="visual">📊 <strong>Visual:</strong> ${p.visual_html}</div>` : ''}
</div>`;
card.querySelector('.card-hdr').onclick = () => card.classList.toggle('open');
secEl.appendChild(card);
const link = document.createElement('a');
link.className = 'sb-link';
link.href = '#' + p.slug;
link.innerHTML = `<span class="sb-dot" style="background:var(--${p.severity}-bdr)"></span>${p.title}`;
link.onclick = e => { e.preventDefault(); document.getElementById(p.slug)?.scrollIntoView({behavior:'smooth'}); card.classList.add('open'); };
sbSec.appendChild(link);
});
root.appendChild(secEl);
sb.appendChild(sbSec);
});
}
document.querySelectorAll('.fchip').forEach(b => {
b.onclick = () => {
if (b.dataset.f === 'all') {
document.querySelectorAll('.fchip').forEach(x => x.classList.toggle('on', x.dataset.f === 'all'));
} else {
document.querySelector('.fchip[data-f="all"]').classList.remove('on');
b.classList.toggle('on');
if (!document.querySelectorAll('.fchip.on').length) document.querySelector('.fchip[data-f="all"]').classList.add('on');
}
render();
};
});
document.getElementById('q').oninput = render;
document.getElementById('theme').onclick = () => {
const d = document.documentElement;
const dark = d.dataset.theme ? d.dataset.theme === 'light' : !matchMedia('(prefers-color-scheme:dark)').matches;
d.dataset.theme = dark ? 'dark' : 'light';
localStorage.setItem('qf-color-theme', d.dataset.theme);
};
const saved = localStorage.getItem('qf-color-theme');
if (saved) document.documentElement.dataset.theme = saved;
let expanded = false;
document.getElementById('expand').onclick = () => {
expanded = !expanded;
document.querySelectorAll('.card').forEach(c => c.classList.toggle('open', expanded));
document.getElementById('expand').textContent = expanded ? 'Collapse all' : 'Expand all';
};
// Default: show critical + high for drill focus; user can click All
document.querySelectorAll('.fchip').forEach(x => x.classList.remove('on'));
['critical','high','important','pattern'].forEach(f => document.querySelector(`.fchip[data-f="${f}"]`)?.classList.add('on'));
render();
routeHash();
</script>
</body>
</html>