[{"data":1,"prerenderedAt":9834},["ShallowReactive",2],{"footer-blog-posts":3,"blog-/blog/real-time-data-pipeline-guide":3626,"blog-related-/blog/real-time-data-pipeline-guide":5935},[4,2422],{"id":5,"title":6,"author":7,"body":10,"category":2406,"coverImage":2407,"date":2408,"description":2409,"extension":2410,"featured":2411,"meta":2412,"navigation":365,"path":2413,"readingTime":2414,"seo":2415,"stem":2416,"tags":2417,"__hash__":2421},"blog/blog/api-first-approach-guide.md","The API-First Approach: Why Leading Companies Build APIs Before Interfaces",{"name":8,"role":9},"Sahan De Silva","Lead Cloud Architect",{"type":11,"value":12,"toc":2373},"minimark",[13,18,27,30,36,40,43,46,68,71,75,78,83,89,95,99,104,109,113,118,123,212,216,219,223,226,235,239,242,246,254,262,266,269,273,276,280,283,1086,1089,1093,1096,1158,1161,1172,1176,1179,1667,1670,1674,1677,1689,1698,1707,1710,1725,1729,1732,1927,1930,1950,1955,1959,1962,1966,2010,2018,2022,2025,2029,2032,2036,2051,2055,2058,2169,2172,2176,2184,2188,2195,2303,2306,2310,2313,2345,2348,2356,2359,2369],[14,15,17],"h2",{"id":16},"apis-are-products-not-plumbing","APIs Are Products, Not Plumbing",[19,20,21,22,26],"p",{},"The most successful software companies in the world — Stripe, Twilio, Shopify — share a common trait: they treat their APIs as first-class products. The ",[23,24,25],"strong",{},"API-first approach"," means designing the API contract before writing any implementation code, ensuring that every system, team, and future integration builds on a stable, well-documented foundation. This methodology is no longer a luxury for platform companies. It is essential for any business building interconnected digital systems that need to scale.",[19,28,29],{},"If you have ever struggled with a mobile app that does not match the web experience, a third-party integration that breaks after every release, or frontend and backend teams blocking each other's progress, API-first development solves these problems by design.",[31,32,33],"blockquote",{},[19,34,35],{},"The best time to adopt API-first was at the start of your project. The second-best time is now, before your next breaking change costs you a customer.",[14,37,39],{"id":38},"what-is-api-first-development","What Is API-First Development?",[19,41,42],{},"API-first development is a methodology where the API specification is designed, reviewed, and agreed upon before any implementation work begins. The API contract becomes the single source of truth that all teams — frontend, backend, mobile, QA, and external partners — build against.",[19,44,45],{},"This inverts the traditional approach where APIs are an afterthought, bolted onto existing backend code and shaped by database schemas rather than consumer needs. In an API-first workflow:",[47,48,49,53,56,59,62,65],"ol",{},[50,51,52],"li",{},"Stakeholders agree on the API contract (what data goes in, what comes out, what errors are possible)",[50,54,55],{},"The contract is documented in a machine-readable specification (OpenAPI, GraphQL SDL)",[50,57,58],{},"Mock servers are generated from the specification, enabling parallel development",[50,60,61],{},"Frontend, mobile, and backend teams build simultaneously against the contract",[50,63,64],{},"Contract tests verify that implementations match the specification",[50,66,67],{},"The API is versioned and maintained as a product, with its own lifecycle",[19,69,70],{},"This approach fundamentally changes how teams collaborate, how quickly features ship, and how reliably systems integrate.",[14,72,74],{"id":73},"api-first-vs-code-first-what-changes","API-First vs Code-First: What Changes",[19,76,77],{},"The differences between API-first and code-first development are practical, not just philosophical. Here is how each phase of development changes.",[79,80,82],"h3",{"id":81},"design-phase","Design Phase",[19,84,85,88],{},[23,86,87],{},"Code-first",": A backend developer builds an endpoint, documents it in a wiki or Swagger annotation, and shares it with the frontend team. The frontend team discovers edge cases, requests changes, and both teams iterate — often through a slow cycle of PRs, Slack messages, and meetings.",[19,90,91,94],{},[23,92,93],{},"API-first",": Stakeholders (product, frontend, backend, mobile) review the API specification together before any code is written. Disagreements about data shapes, naming conventions, and error handling are resolved in a document, not in pull requests. Mock servers let everyone validate the design against real use cases.",[79,96,98],{"id":97},"development-phase","Development Phase",[19,100,101,103],{},[23,102,87],{},": Frontend teams wait for backend endpoints to be ready. This creates sequential dependencies and idle time. When the backend delivers an endpoint, its shape often does not match frontend expectations, triggering rework.",[19,105,106,108],{},[23,107,93],{},": Frontend and backend teams work in parallel from day one. The frontend builds against mock servers generated from the specification. The backend implements against the same specification. When both sides are done, integration is a formality because the contract was agreed upon upfront.",[79,110,112],{"id":111},"testing-phase","Testing Phase",[19,114,115,117],{},[23,116,87],{},": Integration tests are written after both sides are built, discovering contract mismatches late in the cycle.",[19,119,120,122],{},[23,121,93],{},": Contract tests run continuously, verifying that implementations conform to the specification. Consumer-driven contract testing ensures that API changes do not break existing consumers.",[124,125,126,142],"table",{},[127,128,129],"thead",{},[130,131,132,136,139],"tr",{},[133,134,135],"th",{},"Aspect",[133,137,138],{},"Code-First",[133,140,141],{},"API-First",[143,144,145,157,168,179,190,201],"tbody",{},[130,146,147,151,154],{},[148,149,150],"td",{},"Design input",[148,152,153],{},"Backend developer",[148,155,156],{},"Cross-functional stakeholders",[130,158,159,162,165],{},[148,160,161],{},"Specification",[148,163,164],{},"Generated from code (afterthought)",[148,166,167],{},"Written first (source of truth)",[130,169,170,173,176],{},[148,171,172],{},"Parallel development",[148,174,175],{},"Limited (sequential dependencies)",[148,177,178],{},"Full (mock servers from day one)",[130,180,181,184,187],{},[148,182,183],{},"Contract validation",[148,185,186],{},"Manual / late integration testing",[148,188,189],{},"Automated contract testing",[130,191,192,195,198],{},[148,193,194],{},"Documentation",[148,196,197],{},"Often stale",[148,199,200],{},"Always current (generated from spec)",[130,202,203,206,209],{},[148,204,205],{},"Breaking change risk",[148,207,208],{},"High (discovered in production)",[148,210,211],{},"Low (caught in CI)",[14,213,215],{"id":214},"the-business-case-for-api-first","The Business Case for API-First",[19,217,218],{},"API-first development is not just an engineering preference. It delivers measurable business value across multiple dimensions.",[79,220,222],{"id":221},"faster-parallel-development","Faster Parallel Development",[19,224,225],{},"When frontend and backend teams can work simultaneously, feature delivery accelerates by 30-50%. There is no \"waiting for the API\" phase. Mobile developers are not blocked by web developers. External partners can start integration work before your internal implementation is complete.",[19,227,228,229,234],{},"For businesses working with an ",[230,231,233],"a",{"href":232},"/solutions/api-integrations","integration engineering partner",", this parallel development capability is transformative. It compresses timelines and reduces the coordination overhead that slows most projects.",[79,236,238],{"id":237},"better-partner-and-third-party-integrations","Better Partner and Third-Party Integrations",[19,240,241],{},"If your business relies on third-party integrations — payment processors, shipping providers, CRM systems, marketing platforms — a well-designed API layer makes these integrations predictable and maintainable. Partners build against your documented API, not against the quirks of your internal implementation.",[79,243,245],{"id":244},"future-proofing-your-technology-stack","Future-Proofing Your Technology Stack",[19,247,248,249,253],{},"A well-designed API layer decouples your business logic from any specific frontend or consumer. Today, your API serves a web application. Tomorrow, it serves a mobile app, an AI agent like ",[230,250,252],{"href":251},"/solutions/connekz-integration","Connekz",", an IoT device, or a partner's platform — all without changing the backend.",[19,255,256,257,261],{},"This flexibility is particularly valuable for businesses planning ",[230,258,260],{"href":259},"/solutions/mobile-apps","mobile application development",". When the API is designed independently of the web frontend, the mobile app gets the same first-class data access without workarounds or BFF (Backend for Frontend) layers.",[79,263,265],{"id":264},"reduced-rework-and-miscommunication","Reduced Rework and Miscommunication",[19,267,268],{},"The most expensive bugs are specification bugs — building the wrong thing. API-first development forces specification alignment before code is written. The cost of changing a YAML file is trivially small compared to refactoring implemented code across multiple teams and codebases.",[14,270,272],{"id":271},"implementation-patterns","Implementation Patterns",[19,274,275],{},"Moving from theory to practice requires specific tools, patterns, and workflows. Here is how to implement API-first development in your organisation.",[79,277,279],{"id":278},"openapi-specification-design","OpenAPI Specification Design",[19,281,282],{},"The OpenAPI Specification (formerly Swagger) is the industry standard for describing REST APIs. Your API specification should be the first artifact created for any new feature or service.",[284,285,290],"pre",{"className":286,"code":287,"language":288,"meta":289,"style":289},"language-yaml shiki shiki-themes github-light github-dark","# openapi.yaml — Example specification for a booking API\nopenapi: 3.1.0\ninfo:\n  title: Booking API\n  version: 2.0.0\n  description: API for managing customer bookings and appointments\n\npaths:\n  /bookings:\n    post:\n      operationId: createBooking\n      summary: Create a new booking\n      tags:\n        - Bookings\n      requestBody:\n        required: true\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/CreateBookingRequest'\n      responses:\n        '201':\n          description: Booking created successfully\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/BookingResponse'\n        '409':\n          description: Time slot no longer available\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/ErrorResponse'\n        '422':\n          description: Validation error\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/ValidationErrorResponse'\n\ncomponents:\n  schemas:\n    CreateBookingRequest:\n      type: object\n      required:\n        - serviceType\n        - dateTime\n        - customerName\n        - customerEmail\n      properties:\n        serviceType:\n          type: string\n          enum:\n            - consultation\n            - follow-up\n            - treatment\n        dateTime:\n          type: string\n          format: date-time\n          description: ISO 8601 date-time for the appointment\n        customerName:\n          type: string\n          minLength: 2\n          maxLength: 100\n        customerEmail:\n          type: string\n          format: email\n        notes:\n          type: string\n          maxLength: 500\n\n    BookingResponse:\n      type: object\n      properties:\n        id:\n          type: string\n          format: uuid\n        status:\n          type: string\n          enum:\n            - confirmed\n            - pending\n            - cancelled\n        serviceType:\n          type: string\n        dateTime:\n          type: string\n          format: date-time\n        createdAt:\n          type: string\n          format: date-time\n","yaml","",[291,292,293,302,317,326,338,349,360,367,375,383,391,402,413,421,430,438,449,457,465,473,484,492,500,511,519,527,535,546,554,564,571,578,585,595,603,613,620,627,634,644,649,657,665,673,684,692,700,708,716,724,732,740,751,759,768,776,784,792,801,812,822,830,839,850,861,869,878,888,896,905,915,920,928,937,944,952,961,971,979,988,995,1003,1011,1019,1026,1035,1042,1051,1060,1068,1077],"code",{"__ignoreMap":289},[294,295,298],"span",{"class":296,"line":297},"line",1,[294,299,301],{"class":300},"sJ8bj","# openapi.yaml — Example specification for a booking API\n",[294,303,305,309,313],{"class":296,"line":304},2,[294,306,308],{"class":307},"s9eBZ","openapi",[294,310,312],{"class":311},"sVt8B",": ",[294,314,316],{"class":315},"sj4cs","3.1.0\n",[294,318,320,323],{"class":296,"line":319},3,[294,321,322],{"class":307},"info",[294,324,325],{"class":311},":\n",[294,327,329,332,334],{"class":296,"line":328},4,[294,330,331],{"class":307},"  title",[294,333,312],{"class":311},[294,335,337],{"class":336},"sZZnC","Booking API\n",[294,339,341,344,346],{"class":296,"line":340},5,[294,342,343],{"class":307},"  version",[294,345,312],{"class":311},[294,347,348],{"class":315},"2.0.0\n",[294,350,352,355,357],{"class":296,"line":351},6,[294,353,354],{"class":307},"  description",[294,356,312],{"class":311},[294,358,359],{"class":336},"API for managing customer bookings and appointments\n",[294,361,363],{"class":296,"line":362},7,[294,364,366],{"emptyLinePlaceholder":365},true,"\n",[294,368,370,373],{"class":296,"line":369},8,[294,371,372],{"class":307},"paths",[294,374,325],{"class":311},[294,376,378,381],{"class":296,"line":377},9,[294,379,380],{"class":307},"  /bookings",[294,382,325],{"class":311},[294,384,386,389],{"class":296,"line":385},10,[294,387,388],{"class":307},"    post",[294,390,325],{"class":311},[294,392,394,397,399],{"class":296,"line":393},11,[294,395,396],{"class":307},"      operationId",[294,398,312],{"class":311},[294,400,401],{"class":336},"createBooking\n",[294,403,405,408,410],{"class":296,"line":404},12,[294,406,407],{"class":307},"      summary",[294,409,312],{"class":311},[294,411,412],{"class":336},"Create a new booking\n",[294,414,416,419],{"class":296,"line":415},13,[294,417,418],{"class":307},"      tags",[294,420,325],{"class":311},[294,422,424,427],{"class":296,"line":423},14,[294,425,426],{"class":311},"        - ",[294,428,429],{"class":336},"Bookings\n",[294,431,433,436],{"class":296,"line":432},15,[294,434,435],{"class":307},"      requestBody",[294,437,325],{"class":311},[294,439,441,444,446],{"class":296,"line":440},16,[294,442,443],{"class":307},"        required",[294,445,312],{"class":311},[294,447,448],{"class":315},"true\n",[294,450,452,455],{"class":296,"line":451},17,[294,453,454],{"class":307},"        content",[294,456,325],{"class":311},[294,458,460,463],{"class":296,"line":459},18,[294,461,462],{"class":307},"          application/json",[294,464,325],{"class":311},[294,466,468,471],{"class":296,"line":467},19,[294,469,470],{"class":307},"            schema",[294,472,325],{"class":311},[294,474,476,479,481],{"class":296,"line":475},20,[294,477,478],{"class":307},"              $ref",[294,480,312],{"class":311},[294,482,483],{"class":336},"'#/components/schemas/CreateBookingRequest'\n",[294,485,487,490],{"class":296,"line":486},21,[294,488,489],{"class":307},"      responses",[294,491,325],{"class":311},[294,493,495,498],{"class":296,"line":494},22,[294,496,497],{"class":336},"        '201'",[294,499,325],{"class":311},[294,501,503,506,508],{"class":296,"line":502},23,[294,504,505],{"class":307},"          description",[294,507,312],{"class":311},[294,509,510],{"class":336},"Booking created successfully\n",[294,512,514,517],{"class":296,"line":513},24,[294,515,516],{"class":307},"          content",[294,518,325],{"class":311},[294,520,522,525],{"class":296,"line":521},25,[294,523,524],{"class":307},"            application/json",[294,526,325],{"class":311},[294,528,530,533],{"class":296,"line":529},26,[294,531,532],{"class":307},"              schema",[294,534,325],{"class":311},[294,536,538,541,543],{"class":296,"line":537},27,[294,539,540],{"class":307},"                $ref",[294,542,312],{"class":311},[294,544,545],{"class":336},"'#/components/schemas/BookingResponse'\n",[294,547,549,552],{"class":296,"line":548},28,[294,550,551],{"class":336},"        '409'",[294,553,325],{"class":311},[294,555,557,559,561],{"class":296,"line":556},29,[294,558,505],{"class":307},[294,560,312],{"class":311},[294,562,563],{"class":336},"Time slot no longer available\n",[294,565,567,569],{"class":296,"line":566},30,[294,568,516],{"class":307},[294,570,325],{"class":311},[294,572,574,576],{"class":296,"line":573},31,[294,575,524],{"class":307},[294,577,325],{"class":311},[294,579,581,583],{"class":296,"line":580},32,[294,582,532],{"class":307},[294,584,325],{"class":311},[294,586,588,590,592],{"class":296,"line":587},33,[294,589,540],{"class":307},[294,591,312],{"class":311},[294,593,594],{"class":336},"'#/components/schemas/ErrorResponse'\n",[294,596,598,601],{"class":296,"line":597},34,[294,599,600],{"class":336},"        '422'",[294,602,325],{"class":311},[294,604,606,608,610],{"class":296,"line":605},35,[294,607,505],{"class":307},[294,609,312],{"class":311},[294,611,612],{"class":336},"Validation error\n",[294,614,616,618],{"class":296,"line":615},36,[294,617,516],{"class":307},[294,619,325],{"class":311},[294,621,623,625],{"class":296,"line":622},37,[294,624,524],{"class":307},[294,626,325],{"class":311},[294,628,630,632],{"class":296,"line":629},38,[294,631,532],{"class":307},[294,633,325],{"class":311},[294,635,637,639,641],{"class":296,"line":636},39,[294,638,540],{"class":307},[294,640,312],{"class":311},[294,642,643],{"class":336},"'#/components/schemas/ValidationErrorResponse'\n",[294,645,647],{"class":296,"line":646},40,[294,648,366],{"emptyLinePlaceholder":365},[294,650,652,655],{"class":296,"line":651},41,[294,653,654],{"class":307},"components",[294,656,325],{"class":311},[294,658,660,663],{"class":296,"line":659},42,[294,661,662],{"class":307},"  schemas",[294,664,325],{"class":311},[294,666,668,671],{"class":296,"line":667},43,[294,669,670],{"class":307},"    CreateBookingRequest",[294,672,325],{"class":311},[294,674,676,679,681],{"class":296,"line":675},44,[294,677,678],{"class":307},"      type",[294,680,312],{"class":311},[294,682,683],{"class":336},"object\n",[294,685,687,690],{"class":296,"line":686},45,[294,688,689],{"class":307},"      required",[294,691,325],{"class":311},[294,693,695,697],{"class":296,"line":694},46,[294,696,426],{"class":311},[294,698,699],{"class":336},"serviceType\n",[294,701,703,705],{"class":296,"line":702},47,[294,704,426],{"class":311},[294,706,707],{"class":336},"dateTime\n",[294,709,711,713],{"class":296,"line":710},48,[294,712,426],{"class":311},[294,714,715],{"class":336},"customerName\n",[294,717,719,721],{"class":296,"line":718},49,[294,720,426],{"class":311},[294,722,723],{"class":336},"customerEmail\n",[294,725,727,730],{"class":296,"line":726},50,[294,728,729],{"class":307},"      properties",[294,731,325],{"class":311},[294,733,735,738],{"class":296,"line":734},51,[294,736,737],{"class":307},"        serviceType",[294,739,325],{"class":311},[294,741,743,746,748],{"class":296,"line":742},52,[294,744,745],{"class":307},"          type",[294,747,312],{"class":311},[294,749,750],{"class":336},"string\n",[294,752,754,757],{"class":296,"line":753},53,[294,755,756],{"class":307},"          enum",[294,758,325],{"class":311},[294,760,762,765],{"class":296,"line":761},54,[294,763,764],{"class":311},"            - ",[294,766,767],{"class":336},"consultation\n",[294,769,771,773],{"class":296,"line":770},55,[294,772,764],{"class":311},[294,774,775],{"class":336},"follow-up\n",[294,777,779,781],{"class":296,"line":778},56,[294,780,764],{"class":311},[294,782,783],{"class":336},"treatment\n",[294,785,787,790],{"class":296,"line":786},57,[294,788,789],{"class":307},"        dateTime",[294,791,325],{"class":311},[294,793,795,797,799],{"class":296,"line":794},58,[294,796,745],{"class":307},[294,798,312],{"class":311},[294,800,750],{"class":336},[294,802,804,807,809],{"class":296,"line":803},59,[294,805,806],{"class":307},"          format",[294,808,312],{"class":311},[294,810,811],{"class":336},"date-time\n",[294,813,815,817,819],{"class":296,"line":814},60,[294,816,505],{"class":307},[294,818,312],{"class":311},[294,820,821],{"class":336},"ISO 8601 date-time for the appointment\n",[294,823,825,828],{"class":296,"line":824},61,[294,826,827],{"class":307},"        customerName",[294,829,325],{"class":311},[294,831,833,835,837],{"class":296,"line":832},62,[294,834,745],{"class":307},[294,836,312],{"class":311},[294,838,750],{"class":336},[294,840,842,845,847],{"class":296,"line":841},63,[294,843,844],{"class":307},"          minLength",[294,846,312],{"class":311},[294,848,849],{"class":315},"2\n",[294,851,853,856,858],{"class":296,"line":852},64,[294,854,855],{"class":307},"          maxLength",[294,857,312],{"class":311},[294,859,860],{"class":315},"100\n",[294,862,864,867],{"class":296,"line":863},65,[294,865,866],{"class":307},"        customerEmail",[294,868,325],{"class":311},[294,870,872,874,876],{"class":296,"line":871},66,[294,873,745],{"class":307},[294,875,312],{"class":311},[294,877,750],{"class":336},[294,879,881,883,885],{"class":296,"line":880},67,[294,882,806],{"class":307},[294,884,312],{"class":311},[294,886,887],{"class":336},"email\n",[294,889,891,894],{"class":296,"line":890},68,[294,892,893],{"class":307},"        notes",[294,895,325],{"class":311},[294,897,899,901,903],{"class":296,"line":898},69,[294,900,745],{"class":307},[294,902,312],{"class":311},[294,904,750],{"class":336},[294,906,908,910,912],{"class":296,"line":907},70,[294,909,855],{"class":307},[294,911,312],{"class":311},[294,913,914],{"class":315},"500\n",[294,916,918],{"class":296,"line":917},71,[294,919,366],{"emptyLinePlaceholder":365},[294,921,923,926],{"class":296,"line":922},72,[294,924,925],{"class":307},"    BookingResponse",[294,927,325],{"class":311},[294,929,931,933,935],{"class":296,"line":930},73,[294,932,678],{"class":307},[294,934,312],{"class":311},[294,936,683],{"class":336},[294,938,940,942],{"class":296,"line":939},74,[294,941,729],{"class":307},[294,943,325],{"class":311},[294,945,947,950],{"class":296,"line":946},75,[294,948,949],{"class":307},"        id",[294,951,325],{"class":311},[294,953,955,957,959],{"class":296,"line":954},76,[294,956,745],{"class":307},[294,958,312],{"class":311},[294,960,750],{"class":336},[294,962,964,966,968],{"class":296,"line":963},77,[294,965,806],{"class":307},[294,967,312],{"class":311},[294,969,970],{"class":336},"uuid\n",[294,972,974,977],{"class":296,"line":973},78,[294,975,976],{"class":307},"        status",[294,978,325],{"class":311},[294,980,982,984,986],{"class":296,"line":981},79,[294,983,745],{"class":307},[294,985,312],{"class":311},[294,987,750],{"class":336},[294,989,991,993],{"class":296,"line":990},80,[294,992,756],{"class":307},[294,994,325],{"class":311},[294,996,998,1000],{"class":296,"line":997},81,[294,999,764],{"class":311},[294,1001,1002],{"class":336},"confirmed\n",[294,1004,1006,1008],{"class":296,"line":1005},82,[294,1007,764],{"class":311},[294,1009,1010],{"class":336},"pending\n",[294,1012,1014,1016],{"class":296,"line":1013},83,[294,1015,764],{"class":311},[294,1017,1018],{"class":336},"cancelled\n",[294,1020,1022,1024],{"class":296,"line":1021},84,[294,1023,737],{"class":307},[294,1025,325],{"class":311},[294,1027,1029,1031,1033],{"class":296,"line":1028},85,[294,1030,745],{"class":307},[294,1032,312],{"class":311},[294,1034,750],{"class":336},[294,1036,1038,1040],{"class":296,"line":1037},86,[294,1039,789],{"class":307},[294,1041,325],{"class":311},[294,1043,1045,1047,1049],{"class":296,"line":1044},87,[294,1046,745],{"class":307},[294,1048,312],{"class":311},[294,1050,750],{"class":336},[294,1052,1054,1056,1058],{"class":296,"line":1053},88,[294,1055,806],{"class":307},[294,1057,312],{"class":311},[294,1059,811],{"class":336},[294,1061,1063,1066],{"class":296,"line":1062},89,[294,1064,1065],{"class":307},"        createdAt",[294,1067,325],{"class":311},[294,1069,1071,1073,1075],{"class":296,"line":1070},90,[294,1072,745],{"class":307},[294,1074,312],{"class":311},[294,1076,750],{"class":336},[294,1078,1080,1082,1084],{"class":296,"line":1079},91,[294,1081,806],{"class":307},[294,1083,312],{"class":311},[294,1085,811],{"class":336},[19,1087,1088],{},"This specification is machine-readable. From it, you can generate mock servers, client SDKs, validation middleware, and interactive documentation — all automatically.",[79,1090,1092],{"id":1091},"mock-first-development","Mock-First Development",[19,1094,1095],{},"Once the specification is written, generate mock servers so that consumer teams can start building immediately.",[284,1097,1101],{"className":1098,"code":1099,"language":1100,"meta":289,"style":289},"language-bash shiki shiki-themes github-light github-dark","# Generate a mock server from your OpenAPI spec using Prism\nnpx @stoplight/prism-cli mock openapi.yaml --port 4010\n\n# Or use MSW (Mock Service Worker) for frontend testing\n# msw generates handlers from OpenAPI specs\nnpx msw-auto-mock openapi.yaml --output ./src/mocks/handlers.ts\n","bash",[291,1102,1103,1108,1129,1133,1138,1143],{"__ignoreMap":289},[294,1104,1105],{"class":296,"line":297},[294,1106,1107],{"class":300},"# Generate a mock server from your OpenAPI spec using Prism\n",[294,1109,1110,1114,1117,1120,1123,1126],{"class":296,"line":304},[294,1111,1113],{"class":1112},"sScJk","npx",[294,1115,1116],{"class":336}," @stoplight/prism-cli",[294,1118,1119],{"class":336}," mock",[294,1121,1122],{"class":336}," openapi.yaml",[294,1124,1125],{"class":315}," --port",[294,1127,1128],{"class":315}," 4010\n",[294,1130,1131],{"class":296,"line":319},[294,1132,366],{"emptyLinePlaceholder":365},[294,1134,1135],{"class":296,"line":328},[294,1136,1137],{"class":300},"# Or use MSW (Mock Service Worker) for frontend testing\n",[294,1139,1140],{"class":296,"line":340},[294,1141,1142],{"class":300},"# msw generates handlers from OpenAPI specs\n",[294,1144,1145,1147,1150,1152,1155],{"class":296,"line":351},[294,1146,1113],{"class":1112},[294,1148,1149],{"class":336}," msw-auto-mock",[294,1151,1122],{"class":336},[294,1153,1154],{"class":315}," --output",[294,1156,1157],{"class":336}," ./src/mocks/handlers.ts\n",[19,1159,1160],{},"Mock servers return realistic responses based on the schemas in your specification. Frontend developers build against these mocks, confident that the real API will return data in the same shape.",[1162,1163,1165],"callout",{"type":1164},"tip",[19,1166,1167,1168,1171],{},"Invest time in adding ",[291,1169,1170],{},"example"," values to your OpenAPI schemas. Mocks generated from well-annotated specifications are realistic enough that frontend teams can complete full feature development without ever touching the real backend.",[79,1173,1175],{"id":1174},"contract-testing-with-pact","Contract Testing with Pact",[19,1177,1178],{},"Contract testing verifies that API producers and consumers agree on the interface. Pact is the most widely adopted tool for consumer-driven contract testing.",[284,1180,1184],{"className":1181,"code":1182,"language":1183,"meta":289,"style":289},"language-typescript shiki shiki-themes github-light github-dark","// Consumer-side contract test (frontend/mobile team writes this)\nimport { PactV4 } from '@pact-foundation/pact';\n\nconst provider = new PactV4({\n  consumer: 'BookingWebApp',\n  provider: 'BookingAPI',\n});\n\ndescribe('Booking API Contract', () => {\n  it('creates a booking successfully', async () => {\n    await provider\n      .addInteraction()\n      .given('available time slot exists')\n      .uponReceiving('a request to create a booking')\n      .withRequest('POST', '/bookings', (builder) => {\n        builder\n          .headers({ 'Content-Type': 'application/json' })\n          .jsonBody({\n            serviceType: 'consultation',\n            dateTime: '2026-02-17T14:30:00Z',\n            customerName: 'Sarah Chen',\n            customerEmail: 'sarah@example.com',\n          });\n      })\n      .willRespondWith(201, (builder) => {\n        builder.jsonBody({\n          id: provider.like('f47ac10b-58cc-4372-a567-0e02b2c3d479'),\n          status: 'confirmed',\n          serviceType: 'consultation',\n          dateTime: '2026-02-17T14:30:00Z',\n        });\n      })\n      .executeTest(async (mockServer) => {\n        const response = await createBooking(mockServer.url, {\n          serviceType: 'consultation',\n          dateTime: '2026-02-17T14:30:00Z',\n          customerName: 'Sarah Chen',\n          customerEmail: 'sarah@example.com',\n        });\n        expect(response.status).toBe('confirmed');\n      });\n  });\n});\n","typescript",[291,1185,1186,1191,1209,1213,1233,1244,1254,1259,1263,1283,1306,1314,1325,1340,1354,1385,1390,1412,1421,1431,1441,1451,1461,1466,1471,1493,1502,1518,1528,1537,1546,1551,1555,1578,1597,1605,1613,1622,1631,1635,1653,1658,1663],{"__ignoreMap":289},[294,1187,1188],{"class":296,"line":297},[294,1189,1190],{"class":300},"// Consumer-side contract test (frontend/mobile team writes this)\n",[294,1192,1193,1197,1200,1203,1206],{"class":296,"line":304},[294,1194,1196],{"class":1195},"szBVR","import",[294,1198,1199],{"class":311}," { PactV4 } ",[294,1201,1202],{"class":1195},"from",[294,1204,1205],{"class":336}," '@pact-foundation/pact'",[294,1207,1208],{"class":311},";\n",[294,1210,1211],{"class":296,"line":319},[294,1212,366],{"emptyLinePlaceholder":365},[294,1214,1215,1218,1221,1224,1227,1230],{"class":296,"line":328},[294,1216,1217],{"class":1195},"const",[294,1219,1220],{"class":315}," provider",[294,1222,1223],{"class":1195}," =",[294,1225,1226],{"class":1195}," new",[294,1228,1229],{"class":1112}," PactV4",[294,1231,1232],{"class":311},"({\n",[294,1234,1235,1238,1241],{"class":296,"line":340},[294,1236,1237],{"class":311},"  consumer: ",[294,1239,1240],{"class":336},"'BookingWebApp'",[294,1242,1243],{"class":311},",\n",[294,1245,1246,1249,1252],{"class":296,"line":351},[294,1247,1248],{"class":311},"  provider: ",[294,1250,1251],{"class":336},"'BookingAPI'",[294,1253,1243],{"class":311},[294,1255,1256],{"class":296,"line":362},[294,1257,1258],{"class":311},"});\n",[294,1260,1261],{"class":296,"line":369},[294,1262,366],{"emptyLinePlaceholder":365},[294,1264,1265,1268,1271,1274,1277,1280],{"class":296,"line":377},[294,1266,1267],{"class":1112},"describe",[294,1269,1270],{"class":311},"(",[294,1272,1273],{"class":336},"'Booking API Contract'",[294,1275,1276],{"class":311},", () ",[294,1278,1279],{"class":1195},"=>",[294,1281,1282],{"class":311}," {\n",[294,1284,1285,1288,1290,1293,1296,1299,1302,1304],{"class":296,"line":385},[294,1286,1287],{"class":1112},"  it",[294,1289,1270],{"class":311},[294,1291,1292],{"class":336},"'creates a booking successfully'",[294,1294,1295],{"class":311},", ",[294,1297,1298],{"class":1195},"async",[294,1300,1301],{"class":311}," () ",[294,1303,1279],{"class":1195},[294,1305,1282],{"class":311},[294,1307,1308,1311],{"class":296,"line":393},[294,1309,1310],{"class":1195},"    await",[294,1312,1313],{"class":311}," provider\n",[294,1315,1316,1319,1322],{"class":296,"line":404},[294,1317,1318],{"class":311},"      .",[294,1320,1321],{"class":1112},"addInteraction",[294,1323,1324],{"class":311},"()\n",[294,1326,1327,1329,1332,1334,1337],{"class":296,"line":415},[294,1328,1318],{"class":311},[294,1330,1331],{"class":1112},"given",[294,1333,1270],{"class":311},[294,1335,1336],{"class":336},"'available time slot exists'",[294,1338,1339],{"class":311},")\n",[294,1341,1342,1344,1347,1349,1352],{"class":296,"line":423},[294,1343,1318],{"class":311},[294,1345,1346],{"class":1112},"uponReceiving",[294,1348,1270],{"class":311},[294,1350,1351],{"class":336},"'a request to create a booking'",[294,1353,1339],{"class":311},[294,1355,1356,1358,1361,1363,1366,1368,1371,1374,1378,1381,1383],{"class":296,"line":432},[294,1357,1318],{"class":311},[294,1359,1360],{"class":1112},"withRequest",[294,1362,1270],{"class":311},[294,1364,1365],{"class":336},"'POST'",[294,1367,1295],{"class":311},[294,1369,1370],{"class":336},"'/bookings'",[294,1372,1373],{"class":311},", (",[294,1375,1377],{"class":1376},"s4XuR","builder",[294,1379,1380],{"class":311},") ",[294,1382,1279],{"class":1195},[294,1384,1282],{"class":311},[294,1386,1387],{"class":296,"line":440},[294,1388,1389],{"class":311},"        builder\n",[294,1391,1392,1395,1398,1401,1404,1406,1409],{"class":296,"line":451},[294,1393,1394],{"class":311},"          .",[294,1396,1397],{"class":1112},"headers",[294,1399,1400],{"class":311},"({ ",[294,1402,1403],{"class":336},"'Content-Type'",[294,1405,312],{"class":311},[294,1407,1408],{"class":336},"'application/json'",[294,1410,1411],{"class":311}," })\n",[294,1413,1414,1416,1419],{"class":296,"line":459},[294,1415,1394],{"class":311},[294,1417,1418],{"class":1112},"jsonBody",[294,1420,1232],{"class":311},[294,1422,1423,1426,1429],{"class":296,"line":467},[294,1424,1425],{"class":311},"            serviceType: ",[294,1427,1428],{"class":336},"'consultation'",[294,1430,1243],{"class":311},[294,1432,1433,1436,1439],{"class":296,"line":475},[294,1434,1435],{"class":311},"            dateTime: ",[294,1437,1438],{"class":336},"'2026-02-17T14:30:00Z'",[294,1440,1243],{"class":311},[294,1442,1443,1446,1449],{"class":296,"line":486},[294,1444,1445],{"class":311},"            customerName: ",[294,1447,1448],{"class":336},"'Sarah Chen'",[294,1450,1243],{"class":311},[294,1452,1453,1456,1459],{"class":296,"line":494},[294,1454,1455],{"class":311},"            customerEmail: ",[294,1457,1458],{"class":336},"'sarah@example.com'",[294,1460,1243],{"class":311},[294,1462,1463],{"class":296,"line":502},[294,1464,1465],{"class":311},"          });\n",[294,1467,1468],{"class":296,"line":513},[294,1469,1470],{"class":311},"      })\n",[294,1472,1473,1475,1478,1480,1483,1485,1487,1489,1491],{"class":296,"line":521},[294,1474,1318],{"class":311},[294,1476,1477],{"class":1112},"willRespondWith",[294,1479,1270],{"class":311},[294,1481,1482],{"class":315},"201",[294,1484,1373],{"class":311},[294,1486,1377],{"class":1376},[294,1488,1380],{"class":311},[294,1490,1279],{"class":1195},[294,1492,1282],{"class":311},[294,1494,1495,1498,1500],{"class":296,"line":529},[294,1496,1497],{"class":311},"        builder.",[294,1499,1418],{"class":1112},[294,1501,1232],{"class":311},[294,1503,1504,1507,1510,1512,1515],{"class":296,"line":537},[294,1505,1506],{"class":311},"          id: provider.",[294,1508,1509],{"class":1112},"like",[294,1511,1270],{"class":311},[294,1513,1514],{"class":336},"'f47ac10b-58cc-4372-a567-0e02b2c3d479'",[294,1516,1517],{"class":311},"),\n",[294,1519,1520,1523,1526],{"class":296,"line":548},[294,1521,1522],{"class":311},"          status: ",[294,1524,1525],{"class":336},"'confirmed'",[294,1527,1243],{"class":311},[294,1529,1530,1533,1535],{"class":296,"line":556},[294,1531,1532],{"class":311},"          serviceType: ",[294,1534,1428],{"class":336},[294,1536,1243],{"class":311},[294,1538,1539,1542,1544],{"class":296,"line":566},[294,1540,1541],{"class":311},"          dateTime: ",[294,1543,1438],{"class":336},[294,1545,1243],{"class":311},[294,1547,1548],{"class":296,"line":573},[294,1549,1550],{"class":311},"        });\n",[294,1552,1553],{"class":296,"line":580},[294,1554,1470],{"class":311},[294,1556,1557,1559,1562,1564,1566,1569,1572,1574,1576],{"class":296,"line":587},[294,1558,1318],{"class":311},[294,1560,1561],{"class":1112},"executeTest",[294,1563,1270],{"class":311},[294,1565,1298],{"class":1195},[294,1567,1568],{"class":311}," (",[294,1570,1571],{"class":1376},"mockServer",[294,1573,1380],{"class":311},[294,1575,1279],{"class":1195},[294,1577,1282],{"class":311},[294,1579,1580,1583,1586,1588,1591,1594],{"class":296,"line":597},[294,1581,1582],{"class":1195},"        const",[294,1584,1585],{"class":315}," response",[294,1587,1223],{"class":1195},[294,1589,1590],{"class":1195}," await",[294,1592,1593],{"class":1112}," createBooking",[294,1595,1596],{"class":311},"(mockServer.url, {\n",[294,1598,1599,1601,1603],{"class":296,"line":605},[294,1600,1532],{"class":311},[294,1602,1428],{"class":336},[294,1604,1243],{"class":311},[294,1606,1607,1609,1611],{"class":296,"line":615},[294,1608,1541],{"class":311},[294,1610,1438],{"class":336},[294,1612,1243],{"class":311},[294,1614,1615,1618,1620],{"class":296,"line":622},[294,1616,1617],{"class":311},"          customerName: ",[294,1619,1448],{"class":336},[294,1621,1243],{"class":311},[294,1623,1624,1627,1629],{"class":296,"line":629},[294,1625,1626],{"class":311},"          customerEmail: ",[294,1628,1458],{"class":336},[294,1630,1243],{"class":311},[294,1632,1633],{"class":296,"line":636},[294,1634,1550],{"class":311},[294,1636,1637,1640,1643,1646,1648,1650],{"class":296,"line":646},[294,1638,1639],{"class":1112},"        expect",[294,1641,1642],{"class":311},"(response.status).",[294,1644,1645],{"class":1112},"toBe",[294,1647,1270],{"class":311},[294,1649,1525],{"class":336},[294,1651,1652],{"class":311},");\n",[294,1654,1655],{"class":296,"line":651},[294,1656,1657],{"class":311},"      });\n",[294,1659,1660],{"class":296,"line":659},[294,1661,1662],{"class":311},"  });\n",[294,1664,1665],{"class":296,"line":667},[294,1666,1258],{"class":311},[19,1668,1669],{},"The consumer team writes these contract tests. The provider team runs them in their CI pipeline. If a backend change would break a consumer's expectations, the build fails before the change reaches production.",[79,1671,1673],{"id":1672},"api-versioning-strategies","API Versioning Strategies",[19,1675,1676],{},"APIs evolve. Versioning ensures that existing consumers continue to work while new consumers benefit from improvements. There are three common strategies:",[19,1678,1679,1568,1682,1295,1685,1688],{},[23,1680,1681],{},"URL path versioning",[291,1683,1684],{},"/v1/bookings",[291,1686,1687],{},"/v2/bookings","): The simplest and most explicit approach. Easy to route, easy to understand, easy to deprecate. This is what we recommend for most REST APIs.",[19,1690,1691,1568,1694,1697],{},[23,1692,1693],{},"Header versioning",[291,1695,1696],{},"Accept: application/vnd.api.v2+json","): Keeps URLs clean but is harder to discover and test. Better suited for APIs with sophisticated consumers.",[19,1699,1700,1568,1703,1706],{},[23,1701,1702],{},"Query parameter versioning",[291,1704,1705],{},"/bookings?version=2","): Rarely recommended. It conflates versioning with filtering and creates confusing cache behaviour.",[19,1708,1709],{},"Regardless of strategy, follow these rules:",[1711,1712,1713,1716,1719,1722],"ul",{},[50,1714,1715],{},"Never break an existing version without a deprecation period",[50,1717,1718],{},"Version the entire API, not individual endpoints",[50,1720,1721],{},"Provide migration guides for every major version bump",[50,1723,1724],{},"Monitor usage of deprecated versions and communicate sunset timelines",[79,1726,1728],{"id":1727},"rate-limiting-and-security","Rate Limiting and Security",[19,1730,1731],{},"Every production API needs rate limiting and authentication. These are not optional — they are requirements.",[284,1733,1735],{"className":1181,"code":1734,"language":1183,"meta":289,"style":289},"// Rate limiting middleware example (Express/H3)\nimport { createRateLimiter } from './middleware/rate-limiter';\n\nconst apiRateLimiter = createRateLimiter({\n  windowMs: 60 * 1000, // 1 minute\n  maxRequests: 100,     // 100 requests per window\n  keyGenerator: (req) => req.headers['x-api-key'] || req.ip,\n  onLimitReached: (req, res) => {\n    res.status(429).json({\n      error: 'rate_limit_exceeded',\n      message: 'Too many requests. Please retry after the window resets.',\n      retryAfter: res.getHeader('Retry-After'),\n    });\n  },\n});\n",[291,1736,1737,1742,1756,1760,1774,1793,1807,1837,1857,1878,1888,1898,1913,1918,1923],{"__ignoreMap":289},[294,1738,1739],{"class":296,"line":297},[294,1740,1741],{"class":300},"// Rate limiting middleware example (Express/H3)\n",[294,1743,1744,1746,1749,1751,1754],{"class":296,"line":304},[294,1745,1196],{"class":1195},[294,1747,1748],{"class":311}," { createRateLimiter } ",[294,1750,1202],{"class":1195},[294,1752,1753],{"class":336}," './middleware/rate-limiter'",[294,1755,1208],{"class":311},[294,1757,1758],{"class":296,"line":319},[294,1759,366],{"emptyLinePlaceholder":365},[294,1761,1762,1764,1767,1769,1772],{"class":296,"line":328},[294,1763,1217],{"class":1195},[294,1765,1766],{"class":315}," apiRateLimiter",[294,1768,1223],{"class":1195},[294,1770,1771],{"class":1112}," createRateLimiter",[294,1773,1232],{"class":311},[294,1775,1776,1779,1782,1785,1788,1790],{"class":296,"line":340},[294,1777,1778],{"class":311},"  windowMs: ",[294,1780,1781],{"class":315},"60",[294,1783,1784],{"class":1195}," *",[294,1786,1787],{"class":315}," 1000",[294,1789,1295],{"class":311},[294,1791,1792],{"class":300},"// 1 minute\n",[294,1794,1795,1798,1801,1804],{"class":296,"line":351},[294,1796,1797],{"class":311},"  maxRequests: ",[294,1799,1800],{"class":315},"100",[294,1802,1803],{"class":311},",     ",[294,1805,1806],{"class":300},"// 100 requests per window\n",[294,1808,1809,1812,1815,1818,1820,1822,1825,1828,1831,1834],{"class":296,"line":362},[294,1810,1811],{"class":1112},"  keyGenerator",[294,1813,1814],{"class":311},": (",[294,1816,1817],{"class":1376},"req",[294,1819,1380],{"class":311},[294,1821,1279],{"class":1195},[294,1823,1824],{"class":311}," req.headers[",[294,1826,1827],{"class":336},"'x-api-key'",[294,1829,1830],{"class":311},"] ",[294,1832,1833],{"class":1195},"||",[294,1835,1836],{"class":311}," req.ip,\n",[294,1838,1839,1842,1844,1846,1848,1851,1853,1855],{"class":296,"line":369},[294,1840,1841],{"class":1112},"  onLimitReached",[294,1843,1814],{"class":311},[294,1845,1817],{"class":1376},[294,1847,1295],{"class":311},[294,1849,1850],{"class":1376},"res",[294,1852,1380],{"class":311},[294,1854,1279],{"class":1195},[294,1856,1282],{"class":311},[294,1858,1859,1862,1865,1867,1870,1873,1876],{"class":296,"line":377},[294,1860,1861],{"class":311},"    res.",[294,1863,1864],{"class":1112},"status",[294,1866,1270],{"class":311},[294,1868,1869],{"class":315},"429",[294,1871,1872],{"class":311},").",[294,1874,1875],{"class":1112},"json",[294,1877,1232],{"class":311},[294,1879,1880,1883,1886],{"class":296,"line":385},[294,1881,1882],{"class":311},"      error: ",[294,1884,1885],{"class":336},"'rate_limit_exceeded'",[294,1887,1243],{"class":311},[294,1889,1890,1893,1896],{"class":296,"line":393},[294,1891,1892],{"class":311},"      message: ",[294,1894,1895],{"class":336},"'Too many requests. Please retry after the window resets.'",[294,1897,1243],{"class":311},[294,1899,1900,1903,1906,1908,1911],{"class":296,"line":404},[294,1901,1902],{"class":311},"      retryAfter: res.",[294,1904,1905],{"class":1112},"getHeader",[294,1907,1270],{"class":311},[294,1909,1910],{"class":336},"'Retry-After'",[294,1912,1517],{"class":311},[294,1914,1915],{"class":296,"line":415},[294,1916,1917],{"class":311},"    });\n",[294,1919,1920],{"class":296,"line":423},[294,1921,1922],{"class":311},"  },\n",[294,1924,1925],{"class":296,"line":432},[294,1926,1258],{"class":311},[19,1928,1929],{},"For authentication, the choice between API keys, OAuth 2.0, and JWT depends on your consumer types:",[1711,1931,1932,1938,1944],{},[50,1933,1934,1937],{},[23,1935,1936],{},"API keys",": Simple, suitable for server-to-server communication where the consumer is trusted.",[50,1939,1940,1943],{},[23,1941,1942],{},"OAuth 2.0",": Required when third-party applications need delegated access to user data. The authorization code flow with PKCE is the current standard for mobile and web applications.",[50,1945,1946,1949],{},[23,1947,1948],{},"JWT (JSON Web Tokens)",": Efficient for stateless authentication in microservice architectures. Short-lived access tokens with refresh token rotation provide security without constant database lookups.",[1162,1951,1952],{"type":322},[19,1953,1954],{},"API security is not just authentication. It includes input validation, output encoding, CORS configuration, request size limits, and protection against common attacks (injection, BOLA, mass assignment). The OWASP API Security Top 10 is required reading for any team building production APIs.",[14,1956,1958],{"id":1957},"api-documentation-as-a-product","API Documentation as a Product",[19,1960,1961],{},"An API without good documentation is an API nobody will use. Treat your documentation as a product with its own quality standards, user experience, and maintenance schedule.",[79,1963,1965],{"id":1964},"what-great-api-documentation-includes","What Great API Documentation Includes",[1711,1967,1968,1974,1980,1986,1992,1998,2004],{},[50,1969,1970,1973],{},[23,1971,1972],{},"Getting started guide",": A developer should be able to make their first successful API call within 5 minutes of reading your documentation.",[50,1975,1976,1979],{},[23,1977,1978],{},"Authentication guide",": Clear instructions for obtaining and using credentials, with copy-paste examples.",[50,1981,1982,1985],{},[23,1983,1984],{},"Interactive reference",": Every endpoint documented with try-it-out functionality. Tools like Stoplight, Redocly, and Scalar generate these from OpenAPI specifications.",[50,1987,1988,1991],{},[23,1989,1990],{},"Code examples",": In every language your consumers use. At minimum: JavaScript, Python, and cURL.",[50,1993,1994,1997],{},[23,1995,1996],{},"Error reference",": Every possible error code documented with the cause and the recommended resolution.",[50,1999,2000,2003],{},[23,2001,2002],{},"Changelog",": What changed in each version, with migration instructions for breaking changes.",[50,2005,2006,2009],{},[23,2007,2008],{},"SDKs and client libraries",": Auto-generated from your OpenAPI specification and published to npm, PyPI, and other package registries.",[19,2011,2012,2013,2017],{},"For businesses building ",[230,2014,2016],{"href":2015},"/solutions/cloud-native","cloud-native platforms",", a developer portal with interactive API documentation is not a nice-to-have — it is a competitive advantage. Partners and developers choose platforms that are easy to integrate with.",[14,2019,2021],{"id":2020},"common-mistakes-to-avoid","Common Mistakes to Avoid",[19,2023,2024],{},"After designing and reviewing dozens of APIs, we see the same mistakes repeatedly. Here are the most damaging ones.",[79,2026,2028],{"id":2027},"designing-apis-around-database-schemas","Designing APIs Around Database Schemas",[19,2030,2031],{},"Your API should model your business domain, not your database tables. If your API response mirrors a database JOIN with nested foreign keys and auto-increment IDs, you have coupled your public interface to your internal implementation. Every database migration becomes a potential breaking API change.",[79,2033,2035],{"id":2034},"inconsistent-naming-conventions","Inconsistent Naming Conventions",[19,2037,2038,2039,2042,2043,2046,2047,2050],{},"Pick a convention and enforce it everywhere. If you use ",[291,2040,2041],{},"camelCase"," for property names, use it consistently across every endpoint. If you use plural nouns for collection resources (",[291,2044,2045],{},"/bookings",", not ",[291,2048,2049],{},"/booking","), do not suddenly switch to singular elsewhere. Inconsistency forces consumers to guess, which means bugs.",[79,2052,2054],{"id":2053},"missing-pagination","Missing Pagination",[19,2056,2057],{},"Any endpoint that returns a list will eventually return a list too large to process in a single response. Design pagination into your list endpoints from day one — even if your current dataset is small.",[284,2059,2061],{"className":1181,"code":2060,"language":1183,"meta":289,"style":289},"// Cursor-based pagination response\ninterface PaginatedResponse\u003CT> {\n  data: T[];\n  pagination: {\n    cursor: string | null;\n    hasMore: boolean;\n    totalCount: number;\n  };\n}\n\n// Usage: GET /bookings?cursor=abc123&limit=25\n",[291,2062,2063,2068,2085,2099,2108,2126,2138,2150,2155,2160,2164],{"__ignoreMap":289},[294,2064,2065],{"class":296,"line":297},[294,2066,2067],{"class":300},"// Cursor-based pagination response\n",[294,2069,2070,2073,2076,2079,2082],{"class":296,"line":304},[294,2071,2072],{"class":1195},"interface",[294,2074,2075],{"class":1112}," PaginatedResponse",[294,2077,2078],{"class":311},"\u003C",[294,2080,2081],{"class":1112},"T",[294,2083,2084],{"class":311},"> {\n",[294,2086,2087,2090,2093,2096],{"class":296,"line":319},[294,2088,2089],{"class":1376},"  data",[294,2091,2092],{"class":1195},":",[294,2094,2095],{"class":1112}," T",[294,2097,2098],{"class":311},"[];\n",[294,2100,2101,2104,2106],{"class":296,"line":328},[294,2102,2103],{"class":1376},"  pagination",[294,2105,2092],{"class":1195},[294,2107,1282],{"class":311},[294,2109,2110,2113,2115,2118,2121,2124],{"class":296,"line":340},[294,2111,2112],{"class":1376},"    cursor",[294,2114,2092],{"class":1195},[294,2116,2117],{"class":315}," string",[294,2119,2120],{"class":1195}," |",[294,2122,2123],{"class":315}," null",[294,2125,1208],{"class":311},[294,2127,2128,2131,2133,2136],{"class":296,"line":351},[294,2129,2130],{"class":1376},"    hasMore",[294,2132,2092],{"class":1195},[294,2134,2135],{"class":315}," boolean",[294,2137,1208],{"class":311},[294,2139,2140,2143,2145,2148],{"class":296,"line":362},[294,2141,2142],{"class":1376},"    totalCount",[294,2144,2092],{"class":1195},[294,2146,2147],{"class":315}," number",[294,2149,1208],{"class":311},[294,2151,2152],{"class":296,"line":369},[294,2153,2154],{"class":311},"  };\n",[294,2156,2157],{"class":296,"line":377},[294,2158,2159],{"class":311},"}\n",[294,2161,2162],{"class":296,"line":385},[294,2163,366],{"emptyLinePlaceholder":365},[294,2165,2166],{"class":296,"line":393},[294,2167,2168],{"class":300},"// Usage: GET /bookings?cursor=abc123&limit=25\n",[19,2170,2171],{},"Cursor-based pagination is preferred over offset-based for production APIs. It handles insertions and deletions gracefully and performs better on large datasets.",[79,2173,2175],{"id":2174},"breaking-changes-without-versioning","Breaking Changes Without Versioning",[19,2177,2178,2179,2183],{},"Adding a new optional field to a response is not a breaking change. Removing a field, changing a field's type, or altering error response formats ",[2180,2181,2182],"em",{},"are"," breaking changes. If you do not version your API, every breaking change becomes an incident for every consumer simultaneously.",[79,2185,2187],{"id":2186},"ignoring-error-design","Ignoring Error Design",[19,2189,2190,2191,2194],{},"Generic ",[291,2192,2193],{},"500 Internal Server Error"," responses are not acceptable. Every error should include a machine-readable error code, a human-readable message, and enough context for the consumer to take corrective action.",[284,2196,2199],{"className":2197,"code":2198,"language":1875,"meta":289,"style":289},"language-json shiki shiki-themes github-light github-dark","{\n  \"error\": {\n    \"code\": \"BOOKING_SLOT_UNAVAILABLE\",\n    \"message\": \"The requested time slot is no longer available.\",\n    \"details\": {\n      \"requestedDateTime\": \"2026-02-17T14:30:00Z\",\n      \"nextAvailableSlots\": [\n        \"2026-02-17T15:00:00Z\",\n        \"2026-02-17T16:30:00Z\",\n        \"2026-02-18T09:00:00Z\"\n      ]\n    }\n  }\n}\n",[291,2200,2201,2206,2214,2226,2238,2245,2257,2265,2272,2279,2284,2289,2294,2299],{"__ignoreMap":289},[294,2202,2203],{"class":296,"line":297},[294,2204,2205],{"class":311},"{\n",[294,2207,2208,2211],{"class":296,"line":304},[294,2209,2210],{"class":315},"  \"error\"",[294,2212,2213],{"class":311},": {\n",[294,2215,2216,2219,2221,2224],{"class":296,"line":319},[294,2217,2218],{"class":315},"    \"code\"",[294,2220,312],{"class":311},[294,2222,2223],{"class":336},"\"BOOKING_SLOT_UNAVAILABLE\"",[294,2225,1243],{"class":311},[294,2227,2228,2231,2233,2236],{"class":296,"line":328},[294,2229,2230],{"class":315},"    \"message\"",[294,2232,312],{"class":311},[294,2234,2235],{"class":336},"\"The requested time slot is no longer available.\"",[294,2237,1243],{"class":311},[294,2239,2240,2243],{"class":296,"line":340},[294,2241,2242],{"class":315},"    \"details\"",[294,2244,2213],{"class":311},[294,2246,2247,2250,2252,2255],{"class":296,"line":351},[294,2248,2249],{"class":315},"      \"requestedDateTime\"",[294,2251,312],{"class":311},[294,2253,2254],{"class":336},"\"2026-02-17T14:30:00Z\"",[294,2256,1243],{"class":311},[294,2258,2259,2262],{"class":296,"line":362},[294,2260,2261],{"class":315},"      \"nextAvailableSlots\"",[294,2263,2264],{"class":311},": [\n",[294,2266,2267,2270],{"class":296,"line":369},[294,2268,2269],{"class":336},"        \"2026-02-17T15:00:00Z\"",[294,2271,1243],{"class":311},[294,2273,2274,2277],{"class":296,"line":377},[294,2275,2276],{"class":336},"        \"2026-02-17T16:30:00Z\"",[294,2278,1243],{"class":311},[294,2280,2281],{"class":296,"line":385},[294,2282,2283],{"class":336},"        \"2026-02-18T09:00:00Z\"\n",[294,2285,2286],{"class":296,"line":393},[294,2287,2288],{"class":311},"      ]\n",[294,2290,2291],{"class":296,"line":404},[294,2292,2293],{"class":311},"    }\n",[294,2295,2296],{"class":296,"line":415},[294,2297,2298],{"class":311},"  }\n",[294,2300,2301],{"class":296,"line":423},[294,2302,2159],{"class":311},[19,2304,2305],{},"This error response tells the consumer exactly what went wrong and what to do next. It transforms an error from a dead end into a continuation of the user flow.",[14,2307,2309],{"id":2308},"getting-started-with-api-first","Getting Started with API-First",[19,2311,2312],{},"If your organisation currently follows a code-first approach, transitioning to API-first does not require a big-bang migration. Start with your next new service or feature:",[47,2314,2315,2321,2327,2333,2339],{},[50,2316,2317,2320],{},[23,2318,2319],{},"Write the OpenAPI specification first."," Before any implementation code. Share it with all stakeholders for review.",[50,2322,2323,2326],{},[23,2324,2325],{},"Generate mock servers."," Let frontend and mobile teams start building immediately.",[50,2328,2329,2332],{},[23,2330,2331],{},"Implement the backend against the specification."," The spec is the acceptance criteria.",[50,2334,2335,2338],{},[23,2336,2337],{},"Add contract tests to your CI pipeline."," Catch specification drift automatically.",[50,2340,2341,2344],{},[23,2342,2343],{},"Publish interactive documentation."," Make it easy for everyone to understand and use the API.",[19,2346,2347],{},"Once your team experiences the speed and reliability of API-first development on one project, the approach tends to spread organically. Teams that have worked this way rarely want to go back.",[19,2349,2350,2351,2355],{},"For organisations with existing APIs that need restructuring, a ",[230,2352,2354],{"href":2353},"/solutions/web-development","web development engagement"," can help you introduce API-first practices incrementally — redesigning your most critical APIs first and building the tooling and workflows that make the approach sustainable.",[2357,2358],"hr",{},[19,2360,2361],{},[2180,2362,2363,2364,2368],{},"Need to design or rebuild your API layer? ",[230,2365,2367],{"href":2366},"/contact","Talk to our integration engineering team"," about building APIs that scale with your business.",[2370,2371,2372],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":289,"searchDepth":304,"depth":304,"links":2374},[2375,2376,2377,2382,2388,2395,2398,2405],{"id":16,"depth":304,"text":17},{"id":38,"depth":304,"text":39},{"id":73,"depth":304,"text":74,"children":2378},[2379,2380,2381],{"id":81,"depth":319,"text":82},{"id":97,"depth":319,"text":98},{"id":111,"depth":319,"text":112},{"id":214,"depth":304,"text":215,"children":2383},[2384,2385,2386,2387],{"id":221,"depth":319,"text":222},{"id":237,"depth":319,"text":238},{"id":244,"depth":319,"text":245},{"id":264,"depth":319,"text":265},{"id":271,"depth":304,"text":272,"children":2389},[2390,2391,2392,2393,2394],{"id":278,"depth":319,"text":279},{"id":1091,"depth":319,"text":1092},{"id":1174,"depth":319,"text":1175},{"id":1672,"depth":319,"text":1673},{"id":1727,"depth":319,"text":1728},{"id":1957,"depth":304,"text":1958,"children":2396},[2397],{"id":1964,"depth":319,"text":1965},{"id":2020,"depth":304,"text":2021,"children":2399},[2400,2401,2402,2403,2404],{"id":2027,"depth":319,"text":2028},{"id":2034,"depth":319,"text":2035},{"id":2053,"depth":319,"text":2054},{"id":2174,"depth":319,"text":2175},{"id":2186,"depth":319,"text":2187},{"id":2308,"depth":304,"text":2309},"Engineering",null,"2026-02-10","API-first development is reshaping how companies build software. Learn the principles, benefits, and implementation patterns behind this modern approach.","md",false,{},"/blog/api-first-approach-guide","9 min read",{"title":6,"description":2409},"blog/api-first-approach-guide",[2418,141,2419,2420],"API Development","Microservices","Integration","-bqCOEq9ROQy5sCtOFK8kGYzyEJA6yDyJnG38FiWNH4",{"id":2423,"title":2424,"author":2425,"body":2428,"category":3613,"coverImage":2407,"date":3614,"description":3615,"extension":2410,"featured":365,"meta":3616,"navigation":365,"path":3617,"readingTime":3618,"seo":3619,"stem":3620,"tags":3621,"__hash__":3625},"blog/blog/building-connekz-ai-agent.md","Inside Connekz: How We Built an AI Agent That Books, Sells, and Supports",{"name":2426,"role":2427},"Amaya Perera","Head of AI & Machine Learning",{"type":11,"value":2429,"toc":3587},[2430,2434,2440,2443,2448,2452,2455,2459,2462,2466,2469,2473,2476,2479,2483,2486,2489,2515,2837,2842,2846,2849,2852,2856,2859,2863,2866,3177,3181,3184,3187,3252,3255,3260,3264,3267,3271,3274,3278,3285,3289,3292,3296,3299,3325,3329,3332,3335,3355,3358,3362,3365,3368,3382,3385,3389,3392,3424,3427,3431,3434,3517,3524,3533,3537,3540,3570,3573,3575,3584],[14,2431,2433],{"id":2432},"why-we-built-connekz","Why We Built Connekz",[19,2435,2436,2437,2439],{},"Most businesses cannot afford a 24/7 sales and support team, yet their customers expect instant, intelligent responses at any hour. ",[23,2438,252],{}," is the AI agent platform we built to bridge that gap — a system that does not just answer questions, but takes real-world actions: booking appointments, checking availability, processing orders, and updating CRM records, all through natural conversation.",[19,2441,2442],{},"This is the story of how we designed, built, and scaled Connekz from an internal prototype to a production platform serving businesses across New Zealand and beyond. We will cover the architecture decisions, the hard engineering problems, and the lessons we learned shipping AI agents into high-stakes customer-facing environments.",[31,2444,2445],{},[19,2446,2447],{},"Building an AI chatbot is easy. Building an AI agent that businesses trust with their customers and revenue is a fundamentally different problem.",[14,2449,2451],{"id":2450},"the-problem-we-set-out-to-solve","The Problem We Set Out to Solve",[19,2453,2454],{},"Before building Connekz, we spent months interviewing business owners across industries — healthcare clinics, trade services, hospitality, professional services. Three problems appeared consistently.",[79,2456,2458],{"id":2457},"lost-leads-outside-business-hours","Lost leads outside business hours",[19,2460,2461],{},"A physiotherapy clinic we worked with tracked their missed calls. Forty-two percent of new patient enquiries came outside business hours. Every one of those was a potential booking lost to a competitor who answered the phone. Multiplied across hundreds of businesses, the scale of lost revenue was staggering.",[79,2463,2465],{"id":2464},"overwhelmed-support-teams","Overwhelmed support teams",[19,2467,2468],{},"A mid-sized e-commerce company had three customer support staff handling 200+ daily enquiries. Seventy percent of those enquiries were repetitive — order status checks, return policy questions, product availability. The team spent most of their day answering the same questions, leaving complex issues waiting in queue.",[79,2470,2472],{"id":2471},"inconsistent-customer-experiences","Inconsistent customer experiences",[19,2474,2475],{},"When a business operates across multiple channels — phone, email, website chat, social media — customers receive different levels of service depending on which channel they use and which team member responds. Tone, accuracy, and response time vary wildly. There is no single source of truth for how the business should communicate.",[19,2477,2478],{},"Connekz was designed to solve all three problems simultaneously. Not by replacing human teams, but by handling the predictable, repetitive interactions so that human staff can focus on the complex, high-value conversations where they make the biggest difference.",[79,2480,2482],{"id":2481},"rag-pipeline-for-business-specific-knowledge","RAG Pipeline for Business-Specific Knowledge",[19,2484,2485],{},"Every business that deploys Connekz has unique products, services, policies, and terminology. We use Retrieval-Augmented Generation (RAG) to ground the AI agent in business-specific knowledge without fine-tuning a model for each customer.",[19,2487,2488],{},"The RAG pipeline works as follows:",[47,2490,2491,2497,2503,2509],{},[50,2492,2493,2496],{},[23,2494,2495],{},"Ingestion",": Business documents — product catalogues, service descriptions, FAQs, policies, pricing — are processed, chunked, and embedded into a vector database.",[50,2498,2499,2502],{},[23,2500,2501],{},"Retrieval",": When a customer asks a question, the system retrieves the most relevant document chunks based on semantic similarity.",[50,2504,2505,2508],{},[23,2506,2507],{},"Augmented generation",": Retrieved context is injected into the model's prompt alongside the conversation history, grounding the response in verified business information.",[50,2510,2511,2514],{},[23,2512,2513],{},"Citation tracking",": Every factual claim in a response is linked back to its source document, enabling audit trails and accuracy verification.",[284,2516,2518],{"className":1181,"code":2517,"language":1183,"meta":289,"style":289},"// Simplified RAG retrieval pipeline\ninterface RetrievedChunk {\n  content: string;\n  source: string;\n  relevanceScore: number;\n  metadata: Record\u003Cstring, unknown>;\n}\n\nasync function retrieveContext(\n  query: string,\n  businessId: string,\n  topK: number = 5,\n): Promise\u003CRetrievedChunk[]> {\n  const embedding = await embedQuery(query);\n\n  const results = await vectorDb.search({\n    collection: `business_${businessId}`,\n    vector: embedding,\n    topK,\n    filter: { active: true },\n  });\n\n  return results\n    .filter((r) => r.relevanceScore > 0.75)\n    .map((r) => ({\n      content: r.payload.content,\n      source: r.payload.source,\n      relevanceScore: r.score,\n      metadata: r.payload.metadata,\n    }));\n}\n",[291,2519,2520,2525,2534,2545,2556,2567,2590,2594,2598,2611,2622,2633,2649,2667,2685,2689,2708,2724,2729,2734,2745,2749,2753,2761,2790,2808,2813,2818,2823,2828,2833],{"__ignoreMap":289},[294,2521,2522],{"class":296,"line":297},[294,2523,2524],{"class":300},"// Simplified RAG retrieval pipeline\n",[294,2526,2527,2529,2532],{"class":296,"line":304},[294,2528,2072],{"class":1195},[294,2530,2531],{"class":1112}," RetrievedChunk",[294,2533,1282],{"class":311},[294,2535,2536,2539,2541,2543],{"class":296,"line":319},[294,2537,2538],{"class":1376},"  content",[294,2540,2092],{"class":1195},[294,2542,2117],{"class":315},[294,2544,1208],{"class":311},[294,2546,2547,2550,2552,2554],{"class":296,"line":328},[294,2548,2549],{"class":1376},"  source",[294,2551,2092],{"class":1195},[294,2553,2117],{"class":315},[294,2555,1208],{"class":311},[294,2557,2558,2561,2563,2565],{"class":296,"line":340},[294,2559,2560],{"class":1376},"  relevanceScore",[294,2562,2092],{"class":1195},[294,2564,2147],{"class":315},[294,2566,1208],{"class":311},[294,2568,2569,2572,2574,2577,2579,2582,2584,2587],{"class":296,"line":351},[294,2570,2571],{"class":1376},"  metadata",[294,2573,2092],{"class":1195},[294,2575,2576],{"class":1112}," Record",[294,2578,2078],{"class":311},[294,2580,2581],{"class":315},"string",[294,2583,1295],{"class":311},[294,2585,2586],{"class":315},"unknown",[294,2588,2589],{"class":311},">;\n",[294,2591,2592],{"class":296,"line":362},[294,2593,2159],{"class":311},[294,2595,2596],{"class":296,"line":369},[294,2597,366],{"emptyLinePlaceholder":365},[294,2599,2600,2602,2605,2608],{"class":296,"line":377},[294,2601,1298],{"class":1195},[294,2603,2604],{"class":1195}," function",[294,2606,2607],{"class":1112}," retrieveContext",[294,2609,2610],{"class":311},"(\n",[294,2612,2613,2616,2618,2620],{"class":296,"line":385},[294,2614,2615],{"class":1376},"  query",[294,2617,2092],{"class":1195},[294,2619,2117],{"class":315},[294,2621,1243],{"class":311},[294,2623,2624,2627,2629,2631],{"class":296,"line":393},[294,2625,2626],{"class":1376},"  businessId",[294,2628,2092],{"class":1195},[294,2630,2117],{"class":315},[294,2632,1243],{"class":311},[294,2634,2635,2638,2640,2642,2644,2647],{"class":296,"line":404},[294,2636,2637],{"class":1376},"  topK",[294,2639,2092],{"class":1195},[294,2641,2147],{"class":315},[294,2643,1223],{"class":1195},[294,2645,2646],{"class":315}," 5",[294,2648,1243],{"class":311},[294,2650,2651,2654,2656,2659,2661,2664],{"class":296,"line":415},[294,2652,2653],{"class":311},")",[294,2655,2092],{"class":1195},[294,2657,2658],{"class":1112}," Promise",[294,2660,2078],{"class":311},[294,2662,2663],{"class":1112},"RetrievedChunk",[294,2665,2666],{"class":311},"[]> {\n",[294,2668,2669,2672,2675,2677,2679,2682],{"class":296,"line":423},[294,2670,2671],{"class":1195},"  const",[294,2673,2674],{"class":315}," embedding",[294,2676,1223],{"class":1195},[294,2678,1590],{"class":1195},[294,2680,2681],{"class":1112}," embedQuery",[294,2683,2684],{"class":311},"(query);\n",[294,2686,2687],{"class":296,"line":432},[294,2688,366],{"emptyLinePlaceholder":365},[294,2690,2691,2693,2696,2698,2700,2703,2706],{"class":296,"line":440},[294,2692,2671],{"class":1195},[294,2694,2695],{"class":315}," results",[294,2697,1223],{"class":1195},[294,2699,1590],{"class":1195},[294,2701,2702],{"class":311}," vectorDb.",[294,2704,2705],{"class":1112},"search",[294,2707,1232],{"class":311},[294,2709,2710,2713,2716,2719,2722],{"class":296,"line":451},[294,2711,2712],{"class":311},"    collection: ",[294,2714,2715],{"class":336},"`business_${",[294,2717,2718],{"class":311},"businessId",[294,2720,2721],{"class":336},"}`",[294,2723,1243],{"class":311},[294,2725,2726],{"class":296,"line":459},[294,2727,2728],{"class":311},"    vector: embedding,\n",[294,2730,2731],{"class":296,"line":467},[294,2732,2733],{"class":311},"    topK,\n",[294,2735,2736,2739,2742],{"class":296,"line":475},[294,2737,2738],{"class":311},"    filter: { active: ",[294,2740,2741],{"class":315},"true",[294,2743,2744],{"class":311}," },\n",[294,2746,2747],{"class":296,"line":486},[294,2748,1662],{"class":311},[294,2750,2751],{"class":296,"line":494},[294,2752,366],{"emptyLinePlaceholder":365},[294,2754,2755,2758],{"class":296,"line":502},[294,2756,2757],{"class":1195},"  return",[294,2759,2760],{"class":311}," results\n",[294,2762,2763,2766,2769,2772,2775,2777,2779,2782,2785,2788],{"class":296,"line":513},[294,2764,2765],{"class":311},"    .",[294,2767,2768],{"class":1112},"filter",[294,2770,2771],{"class":311},"((",[294,2773,2774],{"class":1376},"r",[294,2776,1380],{"class":311},[294,2778,1279],{"class":1195},[294,2780,2781],{"class":311}," r.relevanceScore ",[294,2783,2784],{"class":1195},">",[294,2786,2787],{"class":315}," 0.75",[294,2789,1339],{"class":311},[294,2791,2792,2794,2797,2799,2801,2803,2805],{"class":296,"line":521},[294,2793,2765],{"class":311},[294,2795,2796],{"class":1112},"map",[294,2798,2771],{"class":311},[294,2800,2774],{"class":1376},[294,2802,1380],{"class":311},[294,2804,1279],{"class":1195},[294,2806,2807],{"class":311}," ({\n",[294,2809,2810],{"class":296,"line":529},[294,2811,2812],{"class":311},"      content: r.payload.content,\n",[294,2814,2815],{"class":296,"line":537},[294,2816,2817],{"class":311},"      source: r.payload.source,\n",[294,2819,2820],{"class":296,"line":548},[294,2821,2822],{"class":311},"      relevanceScore: r.score,\n",[294,2824,2825],{"class":296,"line":556},[294,2826,2827],{"class":311},"      metadata: r.payload.metadata,\n",[294,2829,2830],{"class":296,"line":566},[294,2831,2832],{"class":311},"    }));\n",[294,2834,2835],{"class":296,"line":573},[294,2836,2159],{"class":311},[1162,2838,2839],{"type":322},[19,2840,2841],{},"RAG is not a magic bullet. The quality of retrieved context depends entirely on the quality of the source documents. We invest significant effort in helping clients structure and clean their knowledge base before deployment.",[79,2843,2845],{"id":2844},"voice-and-text-modes","Voice and Text Modes",[19,2847,2848],{},"Connekz operates in both text and voice modes. Text mode powers web chat widgets, WhatsApp integrations, and SMS interactions. Voice mode handles phone calls through real-time speech-to-text, agent processing, and text-to-speech.",[19,2850,2851],{},"Voice introduces additional engineering challenges: turn-taking (knowing when the caller has finished speaking), barge-in handling (the caller interrupts the agent mid-response), and latency requirements (voice conversations feel unnatural if response time exceeds 1.5 seconds).",[14,2853,2855],{"id":2854},"the-tool-calling-system-how-connekz-takes-action","The Tool-Calling System: How Connekz Takes Action",[19,2857,2858],{},"The defining feature that separates Connekz from a standard chatbot is its ability to take real-world actions. When a customer says \"I'd like to book an appointment for next Tuesday,\" Connekz does not just acknowledge the request — it checks the calendar, finds available slots, and creates the booking.",[79,2860,2862],{"id":2861},"how-tool-calling-works","How Tool Calling Works",[19,2864,2865],{},"The AI model is provided with a set of function definitions describing the actions it can take. Each function definition includes a name, description, and a parameter schema. When the model determines that an action is needed, it generates a structured tool call rather than a text response.",[284,2867,2869],{"className":1181,"code":2868,"language":1183,"meta":289,"style":289},"// Tool definition for appointment booking\nconst bookAppointmentTool = {\n  name: 'book_appointment',\n  description:\n    'Books an appointment for a customer. Use this when the customer wants to schedule a visit, consultation, or service.',\n  parameters: {\n    type: 'object',\n    properties: {\n      service_type: {\n        type: 'string',\n        description: 'The type of service requested',\n        enum: ['consultation', 'follow-up', 'initial-assessment', 'treatment'],\n      },\n      preferred_date: {\n        type: 'string',\n        format: 'date',\n        description: 'The customer preferred date (ISO 8601)',\n      },\n      preferred_time_range: {\n        type: 'string',\n        enum: ['morning', 'afternoon', 'evening'],\n        description: 'Preferred time of day',\n      },\n      customer_name: {\n        type: 'string',\n        description: 'Full name of the customer',\n      },\n      customer_phone: {\n        type: 'string',\n        description: 'Contact phone number',\n      },\n      notes: {\n        type: 'string',\n        description: 'Any additional notes or requirements',\n      },\n    },\n    required: ['service_type', 'preferred_date', 'customer_name'],\n  },\n};\n",[291,2870,2871,2876,2887,2897,2902,2909,2914,2924,2929,2934,2944,2954,2979,2984,2989,2997,3007,3016,3020,3025,3033,3052,3061,3065,3070,3078,3087,3091,3096,3104,3113,3117,3122,3130,3139,3143,3148,3168,3172],{"__ignoreMap":289},[294,2872,2873],{"class":296,"line":297},[294,2874,2875],{"class":300},"// Tool definition for appointment booking\n",[294,2877,2878,2880,2883,2885],{"class":296,"line":304},[294,2879,1217],{"class":1195},[294,2881,2882],{"class":315}," bookAppointmentTool",[294,2884,1223],{"class":1195},[294,2886,1282],{"class":311},[294,2888,2889,2892,2895],{"class":296,"line":319},[294,2890,2891],{"class":311},"  name: ",[294,2893,2894],{"class":336},"'book_appointment'",[294,2896,1243],{"class":311},[294,2898,2899],{"class":296,"line":328},[294,2900,2901],{"class":311},"  description:\n",[294,2903,2904,2907],{"class":296,"line":340},[294,2905,2906],{"class":336},"    'Books an appointment for a customer. Use this when the customer wants to schedule a visit, consultation, or service.'",[294,2908,1243],{"class":311},[294,2910,2911],{"class":296,"line":351},[294,2912,2913],{"class":311},"  parameters: {\n",[294,2915,2916,2919,2922],{"class":296,"line":362},[294,2917,2918],{"class":311},"    type: ",[294,2920,2921],{"class":336},"'object'",[294,2923,1243],{"class":311},[294,2925,2926],{"class":296,"line":369},[294,2927,2928],{"class":311},"    properties: {\n",[294,2930,2931],{"class":296,"line":377},[294,2932,2933],{"class":311},"      service_type: {\n",[294,2935,2936,2939,2942],{"class":296,"line":385},[294,2937,2938],{"class":311},"        type: ",[294,2940,2941],{"class":336},"'string'",[294,2943,1243],{"class":311},[294,2945,2946,2949,2952],{"class":296,"line":393},[294,2947,2948],{"class":311},"        description: ",[294,2950,2951],{"class":336},"'The type of service requested'",[294,2953,1243],{"class":311},[294,2955,2956,2959,2961,2963,2966,2968,2971,2973,2976],{"class":296,"line":404},[294,2957,2958],{"class":311},"        enum: [",[294,2960,1428],{"class":336},[294,2962,1295],{"class":311},[294,2964,2965],{"class":336},"'follow-up'",[294,2967,1295],{"class":311},[294,2969,2970],{"class":336},"'initial-assessment'",[294,2972,1295],{"class":311},[294,2974,2975],{"class":336},"'treatment'",[294,2977,2978],{"class":311},"],\n",[294,2980,2981],{"class":296,"line":415},[294,2982,2983],{"class":311},"      },\n",[294,2985,2986],{"class":296,"line":423},[294,2987,2988],{"class":311},"      preferred_date: {\n",[294,2990,2991,2993,2995],{"class":296,"line":432},[294,2992,2938],{"class":311},[294,2994,2941],{"class":336},[294,2996,1243],{"class":311},[294,2998,2999,3002,3005],{"class":296,"line":440},[294,3000,3001],{"class":311},"        format: ",[294,3003,3004],{"class":336},"'date'",[294,3006,1243],{"class":311},[294,3008,3009,3011,3014],{"class":296,"line":451},[294,3010,2948],{"class":311},[294,3012,3013],{"class":336},"'The customer preferred date (ISO 8601)'",[294,3015,1243],{"class":311},[294,3017,3018],{"class":296,"line":459},[294,3019,2983],{"class":311},[294,3021,3022],{"class":296,"line":467},[294,3023,3024],{"class":311},"      preferred_time_range: {\n",[294,3026,3027,3029,3031],{"class":296,"line":475},[294,3028,2938],{"class":311},[294,3030,2941],{"class":336},[294,3032,1243],{"class":311},[294,3034,3035,3037,3040,3042,3045,3047,3050],{"class":296,"line":486},[294,3036,2958],{"class":311},[294,3038,3039],{"class":336},"'morning'",[294,3041,1295],{"class":311},[294,3043,3044],{"class":336},"'afternoon'",[294,3046,1295],{"class":311},[294,3048,3049],{"class":336},"'evening'",[294,3051,2978],{"class":311},[294,3053,3054,3056,3059],{"class":296,"line":494},[294,3055,2948],{"class":311},[294,3057,3058],{"class":336},"'Preferred time of day'",[294,3060,1243],{"class":311},[294,3062,3063],{"class":296,"line":502},[294,3064,2983],{"class":311},[294,3066,3067],{"class":296,"line":513},[294,3068,3069],{"class":311},"      customer_name: {\n",[294,3071,3072,3074,3076],{"class":296,"line":521},[294,3073,2938],{"class":311},[294,3075,2941],{"class":336},[294,3077,1243],{"class":311},[294,3079,3080,3082,3085],{"class":296,"line":529},[294,3081,2948],{"class":311},[294,3083,3084],{"class":336},"'Full name of the customer'",[294,3086,1243],{"class":311},[294,3088,3089],{"class":296,"line":537},[294,3090,2983],{"class":311},[294,3092,3093],{"class":296,"line":548},[294,3094,3095],{"class":311},"      customer_phone: {\n",[294,3097,3098,3100,3102],{"class":296,"line":556},[294,3099,2938],{"class":311},[294,3101,2941],{"class":336},[294,3103,1243],{"class":311},[294,3105,3106,3108,3111],{"class":296,"line":566},[294,3107,2948],{"class":311},[294,3109,3110],{"class":336},"'Contact phone number'",[294,3112,1243],{"class":311},[294,3114,3115],{"class":296,"line":573},[294,3116,2983],{"class":311},[294,3118,3119],{"class":296,"line":580},[294,3120,3121],{"class":311},"      notes: {\n",[294,3123,3124,3126,3128],{"class":296,"line":587},[294,3125,2938],{"class":311},[294,3127,2941],{"class":336},[294,3129,1243],{"class":311},[294,3131,3132,3134,3137],{"class":296,"line":597},[294,3133,2948],{"class":311},[294,3135,3136],{"class":336},"'Any additional notes or requirements'",[294,3138,1243],{"class":311},[294,3140,3141],{"class":296,"line":605},[294,3142,2983],{"class":311},[294,3144,3145],{"class":296,"line":615},[294,3146,3147],{"class":311},"    },\n",[294,3149,3150,3153,3156,3158,3161,3163,3166],{"class":296,"line":622},[294,3151,3152],{"class":311},"    required: [",[294,3154,3155],{"class":336},"'service_type'",[294,3157,1295],{"class":311},[294,3159,3160],{"class":336},"'preferred_date'",[294,3162,1295],{"class":311},[294,3164,3165],{"class":336},"'customer_name'",[294,3167,2978],{"class":311},[294,3169,3170],{"class":296,"line":629},[294,3171,1922],{"class":311},[294,3173,3174],{"class":296,"line":636},[294,3175,3176],{"class":311},"};\n",[79,3178,3180],{"id":3179},"safety-guardrails-and-confirmation-flows","Safety Guardrails and Confirmation Flows",[19,3182,3183],{},"Tool calls that modify data or create commitments always pass through a confirmation flow. The agent presents the proposed action to the customer and waits for explicit confirmation before executing.",[19,3185,3186],{},"For example, a booking flow looks like this:",[47,3188,3189,3195,3204,3210,3215,3220,3225,3230,3235,3240,3247],{},[50,3190,3191,3194],{},[23,3192,3193],{},"Customer",": \"I'd like to book a consultation for next Tuesday afternoon.\"",[50,3196,3197,3200,3201],{},[23,3198,3199],{},"Agent"," (internal): Calls ",[291,3202,3203],{},"check_availability({ date: '2026-02-17', time_range: 'afternoon' })",[50,3205,3206,3209],{},[23,3207,3208],{},"System",": Returns available slots: 1:00 PM, 2:30 PM, 4:00 PM",[50,3211,3212,3214],{},[23,3213,3199],{},": \"I have three afternoon slots available on Tuesday the 17th: 1:00 PM, 2:30 PM, and 4:00 PM. Which works best for you?\"",[50,3216,3217,3219],{},[23,3218,3193],{},": \"2:30 works.\"",[50,3221,3222,3224],{},[23,3223,3199],{},": \"I'll book you in for a consultation at 2:30 PM on Tuesday 17 February. Could I get your full name and a contact number?\"",[50,3226,3227,3229],{},[23,3228,3193],{},": \"Sarah Chen, 021 555 0123.\"",[50,3231,3232,3234],{},[23,3233,3199],{},": \"To confirm: a consultation for Sarah Chen at 2:30 PM on Tuesday 17 February. I'll send a confirmation to 021 555 0123. Shall I go ahead?\"",[50,3236,3237,3239],{},[23,3238,3193],{},": \"Yes please.\"",[50,3241,3242,3200,3244],{},[23,3243,3199],{},[291,3245,3246],{},"book_appointment({ service_type: 'consultation', preferred_date: '2026-02-17', preferred_time_range: 'afternoon', customer_name: 'Sarah Chen', customer_phone: '021 555 0123' })",[50,3248,3249,3251],{},[23,3250,3199],{},": \"You're all booked in. You'll receive a confirmation text shortly. Is there anything else I can help with?\"",[19,3253,3254],{},"The confirmation step is non-negotiable. The agent never creates a booking, processes a payment, or modifies a record without explicit customer approval.",[1162,3256,3257],{"type":1164},[19,3258,3259],{},"Designing confirmation flows is as important as designing the AI model itself. A single incorrect booking damages trust far more than a slow response time. We err heavily on the side of confirming before acting.",[14,3261,3263],{"id":3262},"multi-platform-deployment","Multi-Platform Deployment",[19,3265,3266],{},"Connekz deploys wherever your customers are. Each deployment mode is optimised for its platform while sharing the same core intelligence.",[79,3268,3270],{"id":3269},"web-widget","Web Widget",[19,3272,3273],{},"A lightweight JavaScript widget that embeds in any website. It loads asynchronously (under 30KB initial payload), supports custom theming to match your brand, and works across all modern browsers. The widget communicates with the Connekz backend via WebSocket for real-time conversation.",[79,3275,3277],{"id":3276},"inline-chat","Inline Chat",[19,3279,3280,3281,3284],{},"For businesses that want the AI agent integrated directly into their ",[230,3282,3283],{"href":2353},"website pages"," rather than as a floating widget. The inline mode renders within a designated container element and can be styled to look like a native part of the page.",[14,3286,3288],{"id":3287},"what-we-learned-building-production-ai-agents","What We Learned Building Production AI Agents",[19,3290,3291],{},"Shipping AI agents into production customer-facing environments taught us lessons that no research paper or demo could.",[79,3293,3295],{"id":3294},"hallucination-mitigation-is-an-engineering-problem","Hallucination Mitigation Is an Engineering Problem",[19,3297,3298],{},"LLMs hallucinate. This is a fundamental characteristic, not a bug to be patched. Our mitigation strategy is multi-layered:",[1711,3300,3301,3307,3313,3319],{},[50,3302,3303,3306],{},[23,3304,3305],{},"Constrain the knowledge domain",": The agent only answers questions about topics covered in the RAG knowledge base. For everything else, it responds honestly: \"I don't have information about that. Let me connect you with a team member who can help.\"",[50,3308,3309,3312],{},[23,3310,3311],{},"Fact-check against structured data",": When the agent states a price, availability, or policy, the system cross-references against structured data sources (not just the RAG corpus) before presenting the information.",[50,3314,3315,3318],{},[23,3316,3317],{},"Confidence scoring",": Every response includes an internal confidence score. Below a configurable threshold, the agent flags uncertainty to the customer or escalates to a human.",[50,3320,3321,3324],{},[23,3322,3323],{},"Post-response validation",": A lightweight validation model reviews each response before it is sent, checking for contradictions with known facts and flagging potential hallucinations.",[79,3326,3328],{"id":3327},"graceful-handoff-to-humans-is-not-optional","Graceful Handoff to Humans Is Not Optional",[19,3330,3331],{},"No AI agent can handle every situation. The quality of your handoff process determines whether a complex interaction becomes a satisfied customer or a lost one.",[19,3333,3334],{},"Connekz implements three types of handoff:",[47,3336,3337,3343,3349],{},[50,3338,3339,3342],{},[23,3340,3341],{},"Proactive handoff",": The agent detects it cannot resolve the issue (low confidence, out-of-scope request, detected frustration) and initiates transfer.",[50,3344,3345,3348],{},[23,3346,3347],{},"Customer-requested handoff",": The customer explicitly asks to speak with a person. This is honoured immediately, no friction, no attempts to retain the conversation.",[50,3350,3351,3354],{},[23,3352,3353],{},"Escalation handoff",": A human supervisor monitoring the conversation intervenes and takes over.",[19,3356,3357],{},"In all cases, the full conversation history and context are passed to the human agent. The customer never has to repeat themselves.",[79,3359,3361],{"id":3360},"latency-matters-more-than-you-think","Latency Matters More Than You Think",[19,3363,3364],{},"In conversational AI, perceived intelligence is heavily influenced by response speed. A technically superior response delivered in 5 seconds feels worse than a good response delivered in 800ms. Users begin to disengage after 2 seconds of silence.",[19,3366,3367],{},"We optimise for latency at every layer:",[1711,3369,3370,3373,3376,3379],{},[50,3371,3372],{},"Intent classification completes in under 50ms",[50,3374,3375],{},"RAG retrieval runs in parallel with conversation context assembly",[50,3377,3378],{},"Response streaming begins before the full response is generated",[50,3380,3381],{},"Tool calls execute asynchronously where possible",[19,3383,3384],{},"Our p95 response latency for text interactions is under 1.2 seconds. For voice, we target under 1.5 seconds from end-of-speech detection to start-of-response playback.",[79,3386,3388],{"id":3387},"monitoring-and-continuous-improvement","Monitoring and Continuous Improvement",[19,3390,3391],{},"Deploying an AI agent is not a launch-and-forget operation. We monitor every conversation across multiple dimensions:",[1711,3393,3394,3400,3406,3412,3418],{},[50,3395,3396,3399],{},[23,3397,3398],{},"Resolution rate",": What percentage of conversations reach a successful outcome without human handoff?",[50,3401,3402,3405],{},[23,3403,3404],{},"Accuracy rate",": Human evaluators review volenteraly provided sampled conversations for factual accuracy and appropriateness.",[50,3407,3408,3411],{},[23,3409,3410],{},"Customer satisfaction",": Post-conversation ratings and sentiment analysis.",[50,3413,3414,3417],{},[23,3415,3416],{},"Tool call success rate",": What percentage of bookings, updates, and actions complete successfully?",[50,3419,3420,3423],{},[23,3421,3422],{},"Escalation patterns",": Which topics or scenarios consistently require human handoff? These inform knowledge base improvements and model updates.",[19,3425,3426],{},"We feed these metrics back into a continuous improvement loop. Every week, the lowest-performing conversation patterns are reviewed, and the knowledge base, prompts, and guardrails are updated accordingly.",[14,3428,3430],{"id":3429},"results-our-clients-see","Results Our Clients See",[19,3432,3433],{},"The impact of deploying Connekz varies by industry and use case, but the patterns are consistent.",[124,3435,3436,3449],{},[127,3437,3438],{},[130,3439,3440,3443,3446],{},[133,3441,3442],{},"Metric",[133,3444,3445],{},"Typical Before",[133,3447,3448],{},"Typical After",[143,3450,3451,3462,3473,3484,3495,3506],{},[130,3452,3453,3456,3459],{},[148,3454,3455],{},"After-hours response rate",[148,3457,3458],{},"0% (voicemail/email only)",[148,3460,3461],{},"95%+ instant response",[130,3463,3464,3467,3470],{},[148,3465,3466],{},"Average first response time",[148,3468,3469],{},"4-8 hours",[148,3471,3472],{},"Under 2 seconds",[130,3474,3475,3478,3481],{},[148,3476,3477],{},"Routine enquiry handling",[148,3479,3480],{},"100% human",[148,3482,3483],{},"70-80% automated",[130,3485,3486,3489,3492],{},[148,3487,3488],{},"Booking conversion (after-hours)",[148,3490,3491],{},"Near zero",[148,3493,3494],{},"35-50% of enquiries",[130,3496,3497,3500,3503],{},[148,3498,3499],{},"Support cost per interaction",[148,3501,3502],{},"$8-15",[148,3504,3505],{},"$0.50-2.00",[130,3507,3508,3511,3514],{},[148,3509,3510],{},"Customer satisfaction score",[148,3512,3513],{},"3.8/5.0",[148,3515,3516],{},"4.3/5.0",[19,3518,3519,3520,3523],{},"These numbers represent real outcomes from ",[230,3521,3522],{"href":251},"Connekz deployments"," across healthcare, professional services, and hospitality businesses.",[1162,3525,3526],{"type":322},[19,3527,3528,3529,3532],{},"The most surprising result: customer satisfaction scores typically ",[2180,3530,3531],{},"increase"," after AI agent deployment. Customers prefer an instant, accurate response from an AI over a delayed or inconsistent response from an overwhelmed human team.",[14,3534,3536],{"id":3535},"the-road-ahead","The Road Ahead",[19,3538,3539],{},"Connekz is not a finished product. It is a platform that evolves with advances in AI capabilities and our clients' needs. Our current development priorities include:",[1711,3541,3542,3548,3554,3564],{},[50,3543,3544,3547],{},[23,3545,3546],{},"Multi-agent orchestration",": Complex business processes that require coordination between specialised agents (a booking agent, a billing agent, a technical support agent) working together on a single customer interaction.",[50,3549,3550,3553],{},[23,3551,3552],{},"Proactive outreach",": Connekz initiating conversations based on triggers — appointment reminders, follow-up after service, re-engagement of lapsed customers.",[50,3555,3556,3563],{},[23,3557,3558,3559],{},"Deeper ",[230,3560,3562],{"href":3561},"/solutions/ai-solutions","AI integration",": Connecting Connekz to internal business intelligence, allowing the agent to make data-informed recommendations (e.g., suggesting the most popular service for a new customer based on similar customer patterns).",[50,3565,3566,3569],{},[23,3567,3568],{},"Industry-specific models",": Fine-tuned models for healthcare, legal, and financial services that understand domain-specific terminology, compliance requirements, and interaction patterns.",[19,3571,3572],{},"The gap between what customers expect and what most businesses can deliver is growing. AI agents are not a futuristic concept — they are a practical, deployable solution to a problem that every business faces today.",[2357,3574],{},[19,3576,3577],{},[2180,3578,3579,3580,3583],{},"Ready to deploy Connekz for your business? ",[230,3581,3582],{"href":2366},"Start a conversation with our team"," and see what intelligent automation can do for your customer experience.",[2370,3585,3586],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":289,"searchDepth":304,"depth":304,"links":3588},[3589,3590,3597,3601,3605,3611,3612],{"id":2432,"depth":304,"text":2433},{"id":2450,"depth":304,"text":2451,"children":3591},[3592,3593,3594,3595,3596],{"id":2457,"depth":319,"text":2458},{"id":2464,"depth":319,"text":2465},{"id":2471,"depth":319,"text":2472},{"id":2481,"depth":319,"text":2482},{"id":2844,"depth":319,"text":2845},{"id":2854,"depth":304,"text":2855,"children":3598},[3599,3600],{"id":2861,"depth":319,"text":2862},{"id":3179,"depth":319,"text":3180},{"id":3262,"depth":304,"text":3263,"children":3602},[3603,3604],{"id":3269,"depth":319,"text":3270},{"id":3276,"depth":319,"text":3277},{"id":3287,"depth":304,"text":3288,"children":3606},[3607,3608,3609,3610],{"id":3294,"depth":319,"text":3295},{"id":3327,"depth":319,"text":3328},{"id":3360,"depth":319,"text":3361},{"id":3387,"depth":319,"text":3388},{"id":3429,"depth":304,"text":3430},{"id":3535,"depth":304,"text":3536},"AI","2026-02-07","A behind-the-scenes look at building Connekz — the AI agent platform powering customer interactions for businesses across New Zealand and beyond.",{},"/blog/building-connekz-ai-agent","11 min read",{"title":2424,"description":3615},"blog/building-connekz-ai-agent",[252,3622,3623,3624],"AI Agents","Natural Language Processing","Product Engineering","3dweb7U44CHsXPjufugyInw62GeJ0CMrWfns7Q78EI8",{"id":3627,"title":3628,"author":3629,"body":3632,"category":5922,"coverImage":2407,"date":5923,"description":5924,"extension":2410,"featured":2411,"meta":5925,"navigation":365,"path":5926,"readingTime":3618,"seo":5927,"stem":5928,"tags":5929,"__hash__":5934},"blog/blog/real-time-data-pipeline-guide.md","Building a Real-Time Data Pipeline: Architecture, Tools, and Best Practices",{"name":3630,"role":3631},"Nimal Jayawardena","Senior Software Engineer",{"type":11,"value":3633,"toc":5892},[3634,3638,3641,3644,3652,3656,3659,3780,3785,3799,3804,3818,3821,3826,3830,3833,3837,3840,3846,3852,3858,3861,4322,4325,4746,4751,4755,4758,4764,4770,4776,4779,4805,4809,4812,4818,4824,4830,4836,4840,4843,4853,4859,4865,4871,4875,4878,4882,5024,5028,5156,5161,5165,5168,5172,5175,5525,5529,5532,5552,5556,5559,5591,5595,5598,5601,5633,5637,5644,5648,5651,5655,5658,5662,5665,5683,5687,5690,5716,5720,5723,5749,5754,5758,5761,5774,5777,5805,5811,5817,5820,5824,5827,5833,5839,5845,5851,5857,5861,5864,5879,5889],[14,3635,3637],{"id":3636},"why-batch-processing-is-no-longer-enough","Why Batch Processing Is No Longer Enough",[19,3639,3640],{},"Real-time data pipelines have become the backbone of competitive, data-driven organisations. While batch processing served businesses well for decades — collecting data throughout the day and processing it overnight — the modern business environment demands faster answers. A retailer that waits 24 hours to detect a spike in fraudulent transactions loses money every minute. A logistics company that updates delivery estimates once per hour frustrates customers who expect minute-by-minute accuracy.",[19,3642,3643],{},"The shift from batch to real-time is not about replacing one paradigm with another. It is about recognising that different business questions require different latency guarantees. Some analytics can wait until tomorrow. Others cannot wait 10 seconds. The challenge is building an architecture that handles both gracefully, without doubling your infrastructure costs or your engineering team's cognitive load.",[19,3645,3646,3647,3651],{},"This guide walks you through the architecture, tooling decisions, and operational practices that make real-time ",[230,3648,3650],{"href":3649},"/solutions/data-analytics","data pipelines"," reliable and cost-effective. Whether you are processing thousands of events per second or millions, the foundational patterns remain the same.",[14,3653,3655],{"id":3654},"batch-vs-stream-processing-when-you-need-each","Batch vs Stream Processing: When You Need Each",[19,3657,3658],{},"Batch and stream processing are complementary, not competing approaches. Choosing the right one depends on your latency requirements, data volume, processing complexity, and cost tolerance. Understanding the trade-offs is the first step toward designing the right architecture.",[124,3660,3661,3674],{},[127,3662,3663],{},[130,3664,3665,3668,3671],{},[133,3666,3667],{},"Characteristic",[133,3669,3670],{},"Batch Processing",[133,3672,3673],{},"Stream Processing",[143,3675,3676,3689,3702,3715,3728,3741,3754,3767],{},[130,3677,3678,3683,3686],{},[148,3679,3680],{},[23,3681,3682],{},"Latency",[148,3684,3685],{},"Minutes to hours",[148,3687,3688],{},"Milliseconds to seconds",[130,3690,3691,3696,3699],{},[148,3692,3693],{},[23,3694,3695],{},"Data scope",[148,3697,3698],{},"Processes complete, bounded datasets",[148,3700,3701],{},"Processes unbounded, continuous streams",[130,3703,3704,3709,3712],{},[148,3705,3706],{},[23,3707,3708],{},"Processing model",[148,3710,3711],{},"MapReduce, SQL queries on stored data",[148,3713,3714],{},"Event-driven, windowed aggregations",[130,3716,3717,3722,3725],{},[148,3718,3719],{},[23,3720,3721],{},"Complexity",[148,3723,3724],{},"Lower — well-understood patterns",[148,3726,3727],{},"Higher — ordering, late arrivals, state management",[130,3729,3730,3735,3738],{},[148,3731,3732],{},[23,3733,3734],{},"Cost profile",[148,3736,3737],{},"Predictable — runs on schedule",[148,3739,3740],{},"Variable — scales with event volume",[130,3742,3743,3748,3751],{},[148,3744,3745],{},[23,3746,3747],{},"Error handling",[148,3749,3750],{},"Reprocess entire batch",[148,3752,3753],{},"Dead-letter queues, event replay",[130,3755,3756,3761,3764],{},[148,3757,3758],{},[23,3759,3760],{},"Best for",[148,3762,3763],{},"Historical analysis, ML training, reporting",[148,3765,3766],{},"Fraud detection, monitoring, live dashboards",[130,3768,3769,3774,3777],{},[148,3770,3771],{},[23,3772,3773],{},"Tooling",[148,3775,3776],{},"Spark, Hive, dbt, Airflow",[148,3778,3779],{},"Kafka, Flink, Spark Streaming, Kinesis",[19,3781,3782],{},[23,3783,3784],{},"Use batch processing when:",[1711,3786,3787,3790,3793,3796],{},[50,3788,3789],{},"You need complex transformations across large historical datasets.",[50,3791,3792],{},"Latency of minutes to hours is acceptable.",[50,3794,3795],{},"You are training machine learning models on historical data.",[50,3797,3798],{},"You are generating periodic reports (daily, weekly, monthly).",[19,3800,3801],{},[23,3802,3803],{},"Use stream processing when:",[1711,3805,3806,3809,3812,3815],{},[50,3807,3808],{},"You need sub-second or near-real-time responses.",[50,3810,3811],{},"You are monitoring systems for anomalies, fraud, or operational issues.",[50,3813,3814],{},"You are powering live dashboards or real-time personalisation.",[50,3816,3817],{},"You need to trigger actions based on events as they happen.",[19,3819,3820],{},"Most production architectures use both. The \"Lambda architecture\" — running parallel batch and stream paths — was the original approach, but the industry has increasingly moved toward the \"Kappa architecture,\" where the stream processing layer handles both real-time and historical reprocessing by replaying events from a durable log like Apache Kafka.",[1162,3822,3823],{"type":322},[19,3824,3825],{},"The Kappa architecture simplifies operations by maintaining a single processing path. Instead of debugging discrepancies between batch and stream results, you maintain one pipeline and replay events when you need to reprocess historical data. This is only practical if your event store (typically Kafka) retains data long enough for reprocessing — which, with tiered storage, is now feasible for months or even years of data.",[14,3827,3829],{"id":3828},"anatomy-of-a-real-time-data-pipeline","Anatomy of a Real-Time Data Pipeline",[19,3831,3832],{},"A real-time data pipeline consists of four layers, each with distinct responsibilities. Designing these layers independently allows you to scale, replace, and optimise each one without disrupting the others.",[79,3834,3836],{"id":3835},"_1-ingestion-layer","1. Ingestion Layer",[19,3838,3839],{},"The ingestion layer is responsible for capturing events from source systems and making them available for downstream processing. It must be highly available, horizontally scalable, and durable — losing events is unacceptable in most use cases.",[19,3841,3842,3845],{},[23,3843,3844],{},"Apache Kafka"," is the industry standard for event ingestion. It provides a distributed, fault-tolerant commit log that decouples producers from consumers. Events are written to topics, partitioned for parallelism, and retained for a configurable duration. Kafka's design guarantees ordering within a partition and at-least-once delivery.",[19,3847,3848,3851],{},[23,3849,3850],{},"Amazon Kinesis Data Streams"," is a fully managed alternative on AWS. It removes the operational overhead of managing Kafka clusters but offers less flexibility in configuration and retention. For teams already on AWS who want to minimise operational burden, Kinesis is a pragmatic choice.",[19,3853,3854,3857],{},[23,3855,3856],{},"Google Cloud Pub/Sub"," provides a serverless messaging service with automatic scaling. It uses a push-based model by default (compared to Kafka's pull-based model), which simplifies consumer implementation but can make backpressure management more challenging.",[19,3859,3860],{},"Here is a basic Kafka producer in TypeScript using the KafkaJS library:",[284,3862,3864],{"className":1181,"code":3863,"language":1183,"meta":289,"style":289},"import { Kafka, CompressionTypes } from 'kafkajs';\n\nconst kafka = new Kafka({\n  clientId: 'order-service',\n  brokers: ['kafka-1:9092', 'kafka-2:9092', 'kafka-3:9092'],\n  ssl: true,\n  sasl: {\n    mechanism: 'scram-sha-512',\n    username: process.env.KAFKA_USERNAME!,\n    password: process.env.KAFKA_PASSWORD!,\n  },\n});\n\nconst producer = kafka.producer({\n  idempotent: true, // Ensures exactly-once semantics at the producer level\n});\n\ninterface OrderEvent {\n  orderId: string;\n  customerId: string;\n  items: Array\u003C{ productId: string; quantity: number; price: number }>;\n  total: number;\n  currency: string;\n  timestamp: string;\n}\n\nasync function publishOrderEvent(order: OrderEvent): Promise\u003Cvoid> {\n  await producer.connect();\n\n  await producer.send({\n    topic: 'orders.created',\n    compression: CompressionTypes.LZ4,\n    messages: [\n      {\n        key: order.customerId, // Partition by customer for ordering\n        value: JSON.stringify(order),\n        headers: {\n          'event-type': 'ORDER_CREATED',\n          'schema-version': '2',\n          'correlation-id': crypto.randomUUID(),\n        },\n      },\n    ],\n  });\n}\n",[291,3865,3866,3880,3884,3900,3910,3930,3939,3944,3954,3967,3979,3983,3987,3991,4008,4020,4024,4028,4037,4048,4059,4101,4112,4123,4134,4138,4142,4173,4187,4191,4202,4212,4222,4227,4232,4240,4257,4262,4274,4286,4300,4305,4309,4314,4318],{"__ignoreMap":289},[294,3867,3868,3870,3873,3875,3878],{"class":296,"line":297},[294,3869,1196],{"class":1195},[294,3871,3872],{"class":311}," { Kafka, CompressionTypes } ",[294,3874,1202],{"class":1195},[294,3876,3877],{"class":336}," 'kafkajs'",[294,3879,1208],{"class":311},[294,3881,3882],{"class":296,"line":304},[294,3883,366],{"emptyLinePlaceholder":365},[294,3885,3886,3888,3891,3893,3895,3898],{"class":296,"line":319},[294,3887,1217],{"class":1195},[294,3889,3890],{"class":315}," kafka",[294,3892,1223],{"class":1195},[294,3894,1226],{"class":1195},[294,3896,3897],{"class":1112}," Kafka",[294,3899,1232],{"class":311},[294,3901,3902,3905,3908],{"class":296,"line":328},[294,3903,3904],{"class":311},"  clientId: ",[294,3906,3907],{"class":336},"'order-service'",[294,3909,1243],{"class":311},[294,3911,3912,3915,3918,3920,3923,3925,3928],{"class":296,"line":340},[294,3913,3914],{"class":311},"  brokers: [",[294,3916,3917],{"class":336},"'kafka-1:9092'",[294,3919,1295],{"class":311},[294,3921,3922],{"class":336},"'kafka-2:9092'",[294,3924,1295],{"class":311},[294,3926,3927],{"class":336},"'kafka-3:9092'",[294,3929,2978],{"class":311},[294,3931,3932,3935,3937],{"class":296,"line":351},[294,3933,3934],{"class":311},"  ssl: ",[294,3936,2741],{"class":315},[294,3938,1243],{"class":311},[294,3940,3941],{"class":296,"line":362},[294,3942,3943],{"class":311},"  sasl: {\n",[294,3945,3946,3949,3952],{"class":296,"line":369},[294,3947,3948],{"class":311},"    mechanism: ",[294,3950,3951],{"class":336},"'scram-sha-512'",[294,3953,1243],{"class":311},[294,3955,3956,3959,3962,3965],{"class":296,"line":377},[294,3957,3958],{"class":311},"    username: process.env.",[294,3960,3961],{"class":315},"KAFKA_USERNAME",[294,3963,3964],{"class":1195},"!",[294,3966,1243],{"class":311},[294,3968,3969,3972,3975,3977],{"class":296,"line":385},[294,3970,3971],{"class":311},"    password: process.env.",[294,3973,3974],{"class":315},"KAFKA_PASSWORD",[294,3976,3964],{"class":1195},[294,3978,1243],{"class":311},[294,3980,3981],{"class":296,"line":393},[294,3982,1922],{"class":311},[294,3984,3985],{"class":296,"line":404},[294,3986,1258],{"class":311},[294,3988,3989],{"class":296,"line":415},[294,3990,366],{"emptyLinePlaceholder":365},[294,3992,3993,3995,3998,4000,4003,4006],{"class":296,"line":423},[294,3994,1217],{"class":1195},[294,3996,3997],{"class":315}," producer",[294,3999,1223],{"class":1195},[294,4001,4002],{"class":311}," kafka.",[294,4004,4005],{"class":1112},"producer",[294,4007,1232],{"class":311},[294,4009,4010,4013,4015,4017],{"class":296,"line":432},[294,4011,4012],{"class":311},"  idempotent: ",[294,4014,2741],{"class":315},[294,4016,1295],{"class":311},[294,4018,4019],{"class":300},"// Ensures exactly-once semantics at the producer level\n",[294,4021,4022],{"class":296,"line":440},[294,4023,1258],{"class":311},[294,4025,4026],{"class":296,"line":451},[294,4027,366],{"emptyLinePlaceholder":365},[294,4029,4030,4032,4035],{"class":296,"line":459},[294,4031,2072],{"class":1195},[294,4033,4034],{"class":1112}," OrderEvent",[294,4036,1282],{"class":311},[294,4038,4039,4042,4044,4046],{"class":296,"line":467},[294,4040,4041],{"class":1376},"  orderId",[294,4043,2092],{"class":1195},[294,4045,2117],{"class":315},[294,4047,1208],{"class":311},[294,4049,4050,4053,4055,4057],{"class":296,"line":475},[294,4051,4052],{"class":1376},"  customerId",[294,4054,2092],{"class":1195},[294,4056,2117],{"class":315},[294,4058,1208],{"class":311},[294,4060,4061,4064,4066,4069,4072,4075,4077,4079,4082,4085,4087,4089,4091,4094,4096,4098],{"class":296,"line":486},[294,4062,4063],{"class":1376},"  items",[294,4065,2092],{"class":1195},[294,4067,4068],{"class":1112}," Array",[294,4070,4071],{"class":311},"\u003C{ ",[294,4073,4074],{"class":1376},"productId",[294,4076,2092],{"class":1195},[294,4078,2117],{"class":315},[294,4080,4081],{"class":311},"; ",[294,4083,4084],{"class":1376},"quantity",[294,4086,2092],{"class":1195},[294,4088,2147],{"class":315},[294,4090,4081],{"class":311},[294,4092,4093],{"class":1376},"price",[294,4095,2092],{"class":1195},[294,4097,2147],{"class":315},[294,4099,4100],{"class":311}," }>;\n",[294,4102,4103,4106,4108,4110],{"class":296,"line":494},[294,4104,4105],{"class":1376},"  total",[294,4107,2092],{"class":1195},[294,4109,2147],{"class":315},[294,4111,1208],{"class":311},[294,4113,4114,4117,4119,4121],{"class":296,"line":502},[294,4115,4116],{"class":1376},"  currency",[294,4118,2092],{"class":1195},[294,4120,2117],{"class":315},[294,4122,1208],{"class":311},[294,4124,4125,4128,4130,4132],{"class":296,"line":513},[294,4126,4127],{"class":1376},"  timestamp",[294,4129,2092],{"class":1195},[294,4131,2117],{"class":315},[294,4133,1208],{"class":311},[294,4135,4136],{"class":296,"line":521},[294,4137,2159],{"class":311},[294,4139,4140],{"class":296,"line":529},[294,4141,366],{"emptyLinePlaceholder":365},[294,4143,4144,4146,4148,4151,4153,4156,4158,4160,4162,4164,4166,4168,4171],{"class":296,"line":537},[294,4145,1298],{"class":1195},[294,4147,2604],{"class":1195},[294,4149,4150],{"class":1112}," publishOrderEvent",[294,4152,1270],{"class":311},[294,4154,4155],{"class":1376},"order",[294,4157,2092],{"class":1195},[294,4159,4034],{"class":1112},[294,4161,2653],{"class":311},[294,4163,2092],{"class":1195},[294,4165,2658],{"class":1112},[294,4167,2078],{"class":311},[294,4169,4170],{"class":315},"void",[294,4172,2084],{"class":311},[294,4174,4175,4178,4181,4184],{"class":296,"line":548},[294,4176,4177],{"class":1195},"  await",[294,4179,4180],{"class":311}," producer.",[294,4182,4183],{"class":1112},"connect",[294,4185,4186],{"class":311},"();\n",[294,4188,4189],{"class":296,"line":556},[294,4190,366],{"emptyLinePlaceholder":365},[294,4192,4193,4195,4197,4200],{"class":296,"line":566},[294,4194,4177],{"class":1195},[294,4196,4180],{"class":311},[294,4198,4199],{"class":1112},"send",[294,4201,1232],{"class":311},[294,4203,4204,4207,4210],{"class":296,"line":573},[294,4205,4206],{"class":311},"    topic: ",[294,4208,4209],{"class":336},"'orders.created'",[294,4211,1243],{"class":311},[294,4213,4214,4217,4220],{"class":296,"line":580},[294,4215,4216],{"class":311},"    compression: CompressionTypes.",[294,4218,4219],{"class":315},"LZ4",[294,4221,1243],{"class":311},[294,4223,4224],{"class":296,"line":587},[294,4225,4226],{"class":311},"    messages: [\n",[294,4228,4229],{"class":296,"line":597},[294,4230,4231],{"class":311},"      {\n",[294,4233,4234,4237],{"class":296,"line":605},[294,4235,4236],{"class":311},"        key: order.customerId, ",[294,4238,4239],{"class":300},"// Partition by customer for ordering\n",[294,4241,4242,4245,4248,4251,4254],{"class":296,"line":615},[294,4243,4244],{"class":311},"        value: ",[294,4246,4247],{"class":315},"JSON",[294,4249,4250],{"class":311},".",[294,4252,4253],{"class":1112},"stringify",[294,4255,4256],{"class":311},"(order),\n",[294,4258,4259],{"class":296,"line":622},[294,4260,4261],{"class":311},"        headers: {\n",[294,4263,4264,4267,4269,4272],{"class":296,"line":629},[294,4265,4266],{"class":336},"          'event-type'",[294,4268,312],{"class":311},[294,4270,4271],{"class":336},"'ORDER_CREATED'",[294,4273,1243],{"class":311},[294,4275,4276,4279,4281,4284],{"class":296,"line":636},[294,4277,4278],{"class":336},"          'schema-version'",[294,4280,312],{"class":311},[294,4282,4283],{"class":336},"'2'",[294,4285,1243],{"class":311},[294,4287,4288,4291,4294,4297],{"class":296,"line":646},[294,4289,4290],{"class":336},"          'correlation-id'",[294,4292,4293],{"class":311},": crypto.",[294,4295,4296],{"class":1112},"randomUUID",[294,4298,4299],{"class":311},"(),\n",[294,4301,4302],{"class":296,"line":651},[294,4303,4304],{"class":311},"        },\n",[294,4306,4307],{"class":296,"line":659},[294,4308,2983],{"class":311},[294,4310,4311],{"class":296,"line":667},[294,4312,4313],{"class":311},"    ],\n",[294,4315,4316],{"class":296,"line":675},[294,4317,1662],{"class":311},[294,4319,4320],{"class":296,"line":686},[294,4321,2159],{"class":311},[19,4323,4324],{},"And the corresponding consumer:",[284,4326,4328],{"className":1181,"code":4327,"language":1183,"meta":289,"style":289},"import { Kafka, EachMessagePayload } from 'kafkajs';\n\nconst kafka = new Kafka({\n  clientId: 'analytics-consumer',\n  brokers: ['kafka-1:9092', 'kafka-2:9092', 'kafka-3:9092'],\n});\n\nconst consumer = kafka.consumer({\n  groupId: 'analytics-pipeline',\n  sessionTimeout: 30000,\n  heartbeatInterval: 3000,\n});\n\nasync function startConsumer(): Promise\u003Cvoid> {\n  await consumer.connect();\n  await consumer.subscribe({ topics: ['orders.created'], fromBeginning: false });\n\n  await consumer.run({\n    autoCommit: false, // Manual commit for exactly-once processing\n    eachMessage: async ({ topic, partition, message }: EachMessagePayload) => {\n      const order = JSON.parse(message.value!.toString());\n      const schemaVersion = message.headers?.['schema-version']?.toString();\n\n      try {\n        // Transform and load the event\n        await processOrderEvent(order, schemaVersion);\n\n        // Commit offset only after successful processing\n        await consumer.commitOffsets([\n          { topic, partition, offset: (BigInt(message.offset) + 1n).toString() },\n        ]);\n      } catch (error) {\n        // Send to dead-letter queue on failure\n        await publishToDeadLetterQueue(topic, message, error);\n      }\n    },\n  });\n}\n",[291,4329,4330,4343,4347,4361,4370,4386,4390,4394,4410,4420,4430,4440,4444,4448,4470,4481,4504,4508,4519,4531,4570,4601,4623,4627,4634,4639,4650,4654,4659,4671,4698,4703,4714,4719,4729,4734,4738,4742],{"__ignoreMap":289},[294,4331,4332,4334,4337,4339,4341],{"class":296,"line":297},[294,4333,1196],{"class":1195},[294,4335,4336],{"class":311}," { Kafka, EachMessagePayload } ",[294,4338,1202],{"class":1195},[294,4340,3877],{"class":336},[294,4342,1208],{"class":311},[294,4344,4345],{"class":296,"line":304},[294,4346,366],{"emptyLinePlaceholder":365},[294,4348,4349,4351,4353,4355,4357,4359],{"class":296,"line":319},[294,4350,1217],{"class":1195},[294,4352,3890],{"class":315},[294,4354,1223],{"class":1195},[294,4356,1226],{"class":1195},[294,4358,3897],{"class":1112},[294,4360,1232],{"class":311},[294,4362,4363,4365,4368],{"class":296,"line":328},[294,4364,3904],{"class":311},[294,4366,4367],{"class":336},"'analytics-consumer'",[294,4369,1243],{"class":311},[294,4371,4372,4374,4376,4378,4380,4382,4384],{"class":296,"line":340},[294,4373,3914],{"class":311},[294,4375,3917],{"class":336},[294,4377,1295],{"class":311},[294,4379,3922],{"class":336},[294,4381,1295],{"class":311},[294,4383,3927],{"class":336},[294,4385,2978],{"class":311},[294,4387,4388],{"class":296,"line":351},[294,4389,1258],{"class":311},[294,4391,4392],{"class":296,"line":362},[294,4393,366],{"emptyLinePlaceholder":365},[294,4395,4396,4398,4401,4403,4405,4408],{"class":296,"line":369},[294,4397,1217],{"class":1195},[294,4399,4400],{"class":315}," consumer",[294,4402,1223],{"class":1195},[294,4404,4002],{"class":311},[294,4406,4407],{"class":1112},"consumer",[294,4409,1232],{"class":311},[294,4411,4412,4415,4418],{"class":296,"line":377},[294,4413,4414],{"class":311},"  groupId: ",[294,4416,4417],{"class":336},"'analytics-pipeline'",[294,4419,1243],{"class":311},[294,4421,4422,4425,4428],{"class":296,"line":385},[294,4423,4424],{"class":311},"  sessionTimeout: ",[294,4426,4427],{"class":315},"30000",[294,4429,1243],{"class":311},[294,4431,4432,4435,4438],{"class":296,"line":393},[294,4433,4434],{"class":311},"  heartbeatInterval: ",[294,4436,4437],{"class":315},"3000",[294,4439,1243],{"class":311},[294,4441,4442],{"class":296,"line":404},[294,4443,1258],{"class":311},[294,4445,4446],{"class":296,"line":415},[294,4447,366],{"emptyLinePlaceholder":365},[294,4449,4450,4452,4454,4457,4460,4462,4464,4466,4468],{"class":296,"line":423},[294,4451,1298],{"class":1195},[294,4453,2604],{"class":1195},[294,4455,4456],{"class":1112}," startConsumer",[294,4458,4459],{"class":311},"()",[294,4461,2092],{"class":1195},[294,4463,2658],{"class":1112},[294,4465,2078],{"class":311},[294,4467,4170],{"class":315},[294,4469,2084],{"class":311},[294,4471,4472,4474,4477,4479],{"class":296,"line":432},[294,4473,4177],{"class":1195},[294,4475,4476],{"class":311}," consumer.",[294,4478,4183],{"class":1112},[294,4480,4186],{"class":311},[294,4482,4483,4485,4487,4490,4493,4495,4498,4501],{"class":296,"line":440},[294,4484,4177],{"class":1195},[294,4486,4476],{"class":311},[294,4488,4489],{"class":1112},"subscribe",[294,4491,4492],{"class":311},"({ topics: [",[294,4494,4209],{"class":336},[294,4496,4497],{"class":311},"], fromBeginning: ",[294,4499,4500],{"class":315},"false",[294,4502,4503],{"class":311}," });\n",[294,4505,4506],{"class":296,"line":451},[294,4507,366],{"emptyLinePlaceholder":365},[294,4509,4510,4512,4514,4517],{"class":296,"line":459},[294,4511,4177],{"class":1195},[294,4513,4476],{"class":311},[294,4515,4516],{"class":1112},"run",[294,4518,1232],{"class":311},[294,4520,4521,4524,4526,4528],{"class":296,"line":467},[294,4522,4523],{"class":311},"    autoCommit: ",[294,4525,4500],{"class":315},[294,4527,1295],{"class":311},[294,4529,4530],{"class":300},"// Manual commit for exactly-once processing\n",[294,4532,4533,4536,4538,4540,4543,4546,4548,4551,4553,4556,4559,4561,4564,4566,4568],{"class":296,"line":475},[294,4534,4535],{"class":1112},"    eachMessage",[294,4537,312],{"class":311},[294,4539,1298],{"class":1195},[294,4541,4542],{"class":311}," ({ ",[294,4544,4545],{"class":1376},"topic",[294,4547,1295],{"class":311},[294,4549,4550],{"class":1376},"partition",[294,4552,1295],{"class":311},[294,4554,4555],{"class":1376},"message",[294,4557,4558],{"class":311}," }",[294,4560,2092],{"class":1195},[294,4562,4563],{"class":1112}," EachMessagePayload",[294,4565,1380],{"class":311},[294,4567,1279],{"class":1195},[294,4569,1282],{"class":311},[294,4571,4572,4575,4578,4580,4583,4585,4588,4591,4593,4595,4598],{"class":296,"line":486},[294,4573,4574],{"class":1195},"      const",[294,4576,4577],{"class":315}," order",[294,4579,1223],{"class":1195},[294,4581,4582],{"class":315}," JSON",[294,4584,4250],{"class":311},[294,4586,4587],{"class":1112},"parse",[294,4589,4590],{"class":311},"(message.value",[294,4592,3964],{"class":1195},[294,4594,4250],{"class":311},[294,4596,4597],{"class":1112},"toString",[294,4599,4600],{"class":311},"());\n",[294,4602,4603,4605,4608,4610,4613,4616,4619,4621],{"class":296,"line":494},[294,4604,4574],{"class":1195},[294,4606,4607],{"class":315}," schemaVersion",[294,4609,1223],{"class":1195},[294,4611,4612],{"class":311}," message.headers?.[",[294,4614,4615],{"class":336},"'schema-version'",[294,4617,4618],{"class":311},"]?.",[294,4620,4597],{"class":1112},[294,4622,4186],{"class":311},[294,4624,4625],{"class":296,"line":502},[294,4626,366],{"emptyLinePlaceholder":365},[294,4628,4629,4632],{"class":296,"line":513},[294,4630,4631],{"class":1195},"      try",[294,4633,1282],{"class":311},[294,4635,4636],{"class":296,"line":521},[294,4637,4638],{"class":300},"        // Transform and load the event\n",[294,4640,4641,4644,4647],{"class":296,"line":529},[294,4642,4643],{"class":1195},"        await",[294,4645,4646],{"class":1112}," processOrderEvent",[294,4648,4649],{"class":311},"(order, schemaVersion);\n",[294,4651,4652],{"class":296,"line":537},[294,4653,366],{"emptyLinePlaceholder":365},[294,4655,4656],{"class":296,"line":548},[294,4657,4658],{"class":300},"        // Commit offset only after successful processing\n",[294,4660,4661,4663,4665,4668],{"class":296,"line":556},[294,4662,4643],{"class":1195},[294,4664,4476],{"class":311},[294,4666,4667],{"class":1112},"commitOffsets",[294,4669,4670],{"class":311},"([\n",[294,4672,4673,4676,4679,4682,4685,4688,4691,4693,4695],{"class":296,"line":566},[294,4674,4675],{"class":311},"          { topic, partition, offset: (",[294,4677,4678],{"class":1112},"BigInt",[294,4680,4681],{"class":311},"(message.offset) ",[294,4683,4684],{"class":1195},"+",[294,4686,4687],{"class":315}," 1",[294,4689,4690],{"class":1195},"n",[294,4692,1872],{"class":311},[294,4694,4597],{"class":1112},[294,4696,4697],{"class":311},"() },\n",[294,4699,4700],{"class":296,"line":573},[294,4701,4702],{"class":311},"        ]);\n",[294,4704,4705,4708,4711],{"class":296,"line":580},[294,4706,4707],{"class":311},"      } ",[294,4709,4710],{"class":1195},"catch",[294,4712,4713],{"class":311}," (error) {\n",[294,4715,4716],{"class":296,"line":587},[294,4717,4718],{"class":300},"        // Send to dead-letter queue on failure\n",[294,4720,4721,4723,4726],{"class":296,"line":597},[294,4722,4643],{"class":1195},[294,4724,4725],{"class":1112}," publishToDeadLetterQueue",[294,4727,4728],{"class":311},"(topic, message, error);\n",[294,4730,4731],{"class":296,"line":605},[294,4732,4733],{"class":311},"      }\n",[294,4735,4736],{"class":296,"line":615},[294,4737,3147],{"class":311},[294,4739,4740],{"class":296,"line":622},[294,4741,1662],{"class":311},[294,4743,4744],{"class":296,"line":629},[294,4745,2159],{"class":311},[1162,4747,4748],{"type":1164},[19,4749,4750],{},"Always use manual offset commits in stream processing consumers. Auto-commit can acknowledge events before they are fully processed, leading to data loss if the consumer crashes mid-processing. Manual commits ensure at-least-once delivery semantics.",[79,4752,4754],{"id":4753},"_2-processing-and-transformation-layer","2. Processing and Transformation Layer",[19,4756,4757],{},"The processing layer consumes events from the ingestion layer, transforms them, enriches them with additional context, and prepares them for storage or immediate action. This is where business logic lives.",[19,4759,4760,4763],{},[23,4761,4762],{},"Apache Flink"," is the most capable stream processing framework available. It provides exactly-once processing semantics, sophisticated windowing (tumbling, sliding, session windows), and support for both stream and batch processing in a unified API. Flink's stateful processing model makes it ideal for complex event processing, pattern detection, and real-time aggregations.",[19,4765,4766,4769],{},[23,4767,4768],{},"Spark Structured Streaming"," extends Apache Spark's batch processing model to handle streaming data. If your team already uses Spark for batch analytics, Structured Streaming provides a familiar API. However, it uses a micro-batch model by default, which introduces slightly higher latency compared to Flink's true streaming model.",[19,4771,4772,4775],{},[23,4773,4774],{},"Custom consumers"," (like the KafkaJS example above) are appropriate for simpler transformations. If your processing logic is straightforward — validate, transform, write — a custom consumer avoids the operational overhead of managing a Flink or Spark cluster.",[19,4777,4778],{},"Processing patterns you will encounter:",[1711,4780,4781,4787,4793,4799],{},[50,4782,4783,4786],{},[23,4784,4785],{},"Stateless transformations",": Filtering, mapping, enrichment with external data. Each event is processed independently.",[50,4788,4789,4792],{},[23,4790,4791],{},"Stateful aggregations",": Counting events per user, calculating running averages, maintaining session state. Requires state management and checkpointing.",[50,4794,4795,4798],{},[23,4796,4797],{},"Windowed computations",": Aggregating events over time windows (e.g., \"orders per minute in the last 5 minutes\"). Requires handling late-arriving events.",[50,4800,4801,4804],{},[23,4802,4803],{},"Complex event processing (CEP)",": Detecting patterns across multiple events (e.g., \"three failed login attempts within 60 seconds from different IPs\").",[79,4806,4808],{"id":4807},"_3-storage-layer","3. Storage Layer",[19,4810,4811],{},"The storage layer persists processed data for querying, analysis, and machine learning. The choice of storage technology depends on your query patterns, data volume, and latency requirements.",[19,4813,4814,4817],{},[23,4815,4816],{},"Data lakehouses"," (Databricks, Apache Iceberg on S3/GCS) combine the flexibility of data lakes with the performance of data warehouses. They support both structured and semi-structured data, enable schema evolution, and provide ACID transactions. This is the modern default for most analytical workloads.",[19,4819,4820,4823],{},[23,4821,4822],{},"Time-series databases"," (InfluxDB, TimescaleDB, Amazon Timestream) are optimised for time-stamped data. They excel at storing and querying metrics, sensor data, and event logs where time is the primary dimension. Built-in downsampling and retention policies help manage storage costs.",[19,4825,4826,4829],{},[23,4827,4828],{},"OLAP engines"," (ClickHouse, Apache Druid, Apache Pinot) are designed for low-latency analytical queries on large datasets. They are ideal for powering real-time dashboards where users expect sub-second query responses on billions of rows.",[19,4831,4832,4835],{},[23,4833,4834],{},"Operational databases"," (PostgreSQL, MongoDB) may also receive processed data when it needs to be served directly to applications. For example, a real-time recommendation engine might write personalised scores to a fast key-value store for immediate retrieval.",[79,4837,4839],{"id":4838},"_4-serving-layer","4. Serving Layer",[19,4841,4842],{},"The serving layer makes processed data available to end users and downstream systems. It is the interface between your data pipeline and the rest of your organisation.",[19,4844,4845,4848,4849,4852],{},[23,4846,4847],{},"REST and GraphQL APIs"," expose processed data to applications. An ",[230,4850,4851],{"href":232},"API layer"," can serve pre-computed aggregations, real-time metrics, or query results from your OLAP engine.",[19,4854,4855,4858],{},[23,4856,4857],{},"Dashboards"," (Grafana, Metabase, Looker, Power BI) visualise real-time data for business users. Connect them directly to your OLAP engine or time-series database for live updates.",[19,4860,4861,4864],{},[23,4862,4863],{},"Alerts and notifications"," trigger actions based on real-time conditions. When your pipeline detects an anomaly — a sudden spike in error rates, a fraudulent transaction pattern, an inventory threshold breach — it should notify the right people immediately via Slack, PagerDuty, email, or SMS.",[19,4866,4867,4870],{},[23,4868,4869],{},"Event-driven actions"," are automated responses triggered by pipeline outputs. For example, when the pipeline detects that a customer's order total exceeds a threshold, it might automatically apply a discount code and send a personalised thank-you email.",[14,4872,4874],{"id":4873},"choosing-the-right-tools-a-decision-framework","Choosing the Right Tools: A Decision Framework",[19,4876,4877],{},"The number of tools available for data engineering is overwhelming. Rather than evaluating every option, focus on the dimensions that matter most for your specific requirements: latency, cost, operational complexity, and ecosystem integration.",[79,4879,4881],{"id":4880},"ingestion-kafka-vs-kinesis-vs-pubsub","Ingestion: Kafka vs Kinesis vs Pub/Sub",[124,4883,4884,4898],{},[127,4885,4886],{},[130,4887,4888,4891,4893,4896],{},[133,4889,4890],{},"Factor",[133,4892,3844],{},[133,4894,4895],{},"Amazon Kinesis",[133,4897,3856],{},[143,4899,4900,4915,4930,4946,4961,4977,4993,5009],{},[130,4901,4902,4906,4909,4912],{},[148,4903,4904],{},[23,4905,3682],{},[148,4907,4908],{},"Sub-millisecond",[148,4910,4911],{},"~200ms",[148,4913,4914],{},"~100ms",[130,4916,4917,4922,4925,4928],{},[148,4918,4919],{},[23,4920,4921],{},"Throughput",[148,4923,4924],{},"Millions of events/sec",[148,4926,4927],{},"Thousands per shard",[148,4929,4924],{},[130,4931,4932,4937,4940,4943],{},[148,4933,4934],{},[23,4935,4936],{},"Retention",[148,4938,4939],{},"Configurable (unlimited with tiered storage)",[148,4941,4942],{},"1-365 days",[148,4944,4945],{},"7 days (31 with snapshots)",[130,4947,4948,4953,4956,4959],{},[148,4949,4950],{},[23,4951,4952],{},"Operational overhead",[148,4954,4955],{},"High (self-managed) / Low (Confluent Cloud)",[148,4957,4958],{},"Low (fully managed)",[148,4960,4958],{},[130,4962,4963,4968,4971,4974],{},[148,4964,4965],{},[23,4966,4967],{},"Cost model",[148,4969,4970],{},"Per broker/partition",[148,4972,4973],{},"Per shard-hour + per record",[148,4975,4976],{},"Per message volume",[130,4978,4979,4984,4987,4990],{},[148,4980,4981],{},[23,4982,4983],{},"Ecosystem",[148,4985,4986],{},"Largest — Kafka Connect, Kafka Streams, ksqlDB",[148,4988,4989],{},"AWS-native integrations",[148,4991,4992],{},"GCP-native integrations",[130,4994,4995,5000,5003,5006],{},[148,4996,4997],{},[23,4998,4999],{},"Multi-cloud",[148,5001,5002],{},"Yes (runs anywhere)",[148,5004,5005],{},"AWS only",[148,5007,5008],{},"GCP only (though accessible from anywhere)",[130,5010,5011,5015,5018,5021],{},[148,5012,5013],{},[23,5014,3760],{},[148,5016,5017],{},"High-throughput, multi-cloud, complex topologies",[148,5019,5020],{},"AWS-native, moderate scale",[148,5022,5023],{},"GCP-native, serverless architectures",[79,5025,5027],{"id":5026},"analytics-snowflake-vs-bigquery-vs-databricks","Analytics: Snowflake vs BigQuery vs Databricks",[124,5029,5030,5045],{},[127,5031,5032],{},[130,5033,5034,5036,5039,5042],{},[133,5035,4890],{},[133,5037,5038],{},"Snowflake",[133,5040,5041],{},"BigQuery",[133,5043,5044],{},"Databricks",[143,5046,5047,5062,5078,5094,5109,5125,5141],{},[130,5048,5049,5054,5057,5059],{},[148,5050,5051],{},[23,5052,5053],{},"Query model",[148,5055,5056],{},"SQL",[148,5058,5056],{},[148,5060,5061],{},"SQL + Python/Scala",[130,5063,5064,5069,5072,5075],{},[148,5065,5066],{},[23,5067,5068],{},"Architecture",[148,5070,5071],{},"Separated compute and storage",[148,5073,5074],{},"Serverless",[148,5076,5077],{},"Lakehouse (Delta Lake)",[130,5079,5080,5085,5088,5091],{},[148,5081,5082],{},[23,5083,5084],{},"Real-time ingestion",[148,5086,5087],{},"Snowpipe (near real-time)",[148,5089,5090],{},"Streaming inserts",[148,5092,5093],{},"Structured Streaming",[130,5095,5096,5100,5103,5106],{},[148,5097,5098],{},[23,5099,4967],{},[148,5101,5102],{},"Per-second compute + storage",[148,5104,5105],{},"On-demand per query / flat-rate",[148,5107,5108],{},"Per-cluster + storage",[130,5110,5111,5116,5119,5122],{},[148,5112,5113],{},[23,5114,5115],{},"Streaming support",[148,5117,5118],{},"Limited (micro-batch via Snowpipe)",[148,5120,5121],{},"Native streaming inserts",[148,5123,5124],{},"Native (Spark Streaming)",[130,5126,5127,5132,5135,5138],{},[148,5128,5129],{},[23,5130,5131],{},"ML integration",[148,5133,5134],{},"Snowpark",[148,5136,5137],{},"BigQuery ML",[148,5139,5140],{},"MLflow, native notebooks",[130,5142,5143,5147,5150,5153],{},[148,5144,5145],{},[23,5146,3760],{},[148,5148,5149],{},"SQL-heavy analytics, multi-cloud",[148,5151,5152],{},"GCP-native, serverless analytics",[148,5154,5155],{},"Unified batch + stream + ML",[1162,5157,5158],{"type":1164},[19,5159,5160],{},"Avoid choosing tools based solely on technical capabilities. Factor in your team's existing skills, your cloud provider commitments, and your operational capacity. A managed Kinesis pipeline operated by a two-person team will outperform a self-managed Kafka cluster that nobody has time to maintain.",[14,5162,5164],{"id":5163},"data-quality-and-observability","Data Quality and Observability",[19,5166,5167],{},"A pipeline that delivers incorrect data on time is worse than one that delivers correct data late. Data quality and observability are not afterthoughts — they are core requirements that must be designed into your pipeline from the start.",[79,5169,5171],{"id":5170},"schema-validation","Schema Validation",[19,5173,5174],{},"Every event entering your pipeline should be validated against a schema. Schema registries (Confluent Schema Registry, AWS Glue Schema Registry) enforce contracts between producers and consumers. When a producer tries to publish an event that violates the schema, the publish fails — catching errors at the source rather than downstream.",[284,5176,5178],{"className":1181,"code":5177,"language":1183,"meta":289,"style":289},"// Example: Schema validation using Zod at the consumer level\nimport { z } from 'zod';\n\nconst OrderEventSchema = z.object({\n  orderId: z.string().uuid(),\n  customerId: z.string().uuid(),\n  items: z.array(\n    z.object({\n      productId: z.string(),\n      quantity: z.number().int().positive(),\n      price: z.number().positive(),\n    }),\n  ).min(1),\n  total: z.number().positive(),\n  currency: z.string().length(3),\n  timestamp: z.string().datetime(),\n});\n\ntype OrderEvent = z.infer\u003Ctypeof OrderEventSchema>;\n\nfunction validateEvent(raw: unknown): OrderEvent {\n  const result = OrderEventSchema.safeParse(raw);\n\n  if (!result.success) {\n    // Log validation errors for observability\n    console.error('Schema validation failed:', result.error.issues);\n    throw new SchemaValidationError(result.error);\n  }\n\n  return result.data;\n}\n",[291,5179,5180,5185,5199,5203,5220,5235,5248,5258,5267,5276,5296,5309,5314,5329,5342,5361,5375,5379,5383,5408,5412,5438,5456,5460,5472,5477,5493,5506,5510,5514,5521],{"__ignoreMap":289},[294,5181,5182],{"class":296,"line":297},[294,5183,5184],{"class":300},"// Example: Schema validation using Zod at the consumer level\n",[294,5186,5187,5189,5192,5194,5197],{"class":296,"line":304},[294,5188,1196],{"class":1195},[294,5190,5191],{"class":311}," { z } ",[294,5193,1202],{"class":1195},[294,5195,5196],{"class":336}," 'zod'",[294,5198,1208],{"class":311},[294,5200,5201],{"class":296,"line":319},[294,5202,366],{"emptyLinePlaceholder":365},[294,5204,5205,5207,5210,5212,5215,5218],{"class":296,"line":328},[294,5206,1217],{"class":1195},[294,5208,5209],{"class":315}," OrderEventSchema",[294,5211,1223],{"class":1195},[294,5213,5214],{"class":311}," z.",[294,5216,5217],{"class":1112},"object",[294,5219,1232],{"class":311},[294,5221,5222,5225,5227,5230,5233],{"class":296,"line":340},[294,5223,5224],{"class":311},"  orderId: z.",[294,5226,2581],{"class":1112},[294,5228,5229],{"class":311},"().",[294,5231,5232],{"class":1112},"uuid",[294,5234,4299],{"class":311},[294,5236,5237,5240,5242,5244,5246],{"class":296,"line":351},[294,5238,5239],{"class":311},"  customerId: z.",[294,5241,2581],{"class":1112},[294,5243,5229],{"class":311},[294,5245,5232],{"class":1112},[294,5247,4299],{"class":311},[294,5249,5250,5253,5256],{"class":296,"line":362},[294,5251,5252],{"class":311},"  items: z.",[294,5254,5255],{"class":1112},"array",[294,5257,2610],{"class":311},[294,5259,5260,5263,5265],{"class":296,"line":369},[294,5261,5262],{"class":311},"    z.",[294,5264,5217],{"class":1112},[294,5266,1232],{"class":311},[294,5268,5269,5272,5274],{"class":296,"line":377},[294,5270,5271],{"class":311},"      productId: z.",[294,5273,2581],{"class":1112},[294,5275,4299],{"class":311},[294,5277,5278,5281,5284,5286,5289,5291,5294],{"class":296,"line":385},[294,5279,5280],{"class":311},"      quantity: z.",[294,5282,5283],{"class":1112},"number",[294,5285,5229],{"class":311},[294,5287,5288],{"class":1112},"int",[294,5290,5229],{"class":311},[294,5292,5293],{"class":1112},"positive",[294,5295,4299],{"class":311},[294,5297,5298,5301,5303,5305,5307],{"class":296,"line":393},[294,5299,5300],{"class":311},"      price: z.",[294,5302,5283],{"class":1112},[294,5304,5229],{"class":311},[294,5306,5293],{"class":1112},[294,5308,4299],{"class":311},[294,5310,5311],{"class":296,"line":404},[294,5312,5313],{"class":311},"    }),\n",[294,5315,5316,5319,5322,5324,5327],{"class":296,"line":415},[294,5317,5318],{"class":311},"  ).",[294,5320,5321],{"class":1112},"min",[294,5323,1270],{"class":311},[294,5325,5326],{"class":315},"1",[294,5328,1517],{"class":311},[294,5330,5331,5334,5336,5338,5340],{"class":296,"line":423},[294,5332,5333],{"class":311},"  total: z.",[294,5335,5283],{"class":1112},[294,5337,5229],{"class":311},[294,5339,5293],{"class":1112},[294,5341,4299],{"class":311},[294,5343,5344,5347,5349,5351,5354,5356,5359],{"class":296,"line":432},[294,5345,5346],{"class":311},"  currency: z.",[294,5348,2581],{"class":1112},[294,5350,5229],{"class":311},[294,5352,5353],{"class":1112},"length",[294,5355,1270],{"class":311},[294,5357,5358],{"class":315},"3",[294,5360,1517],{"class":311},[294,5362,5363,5366,5368,5370,5373],{"class":296,"line":440},[294,5364,5365],{"class":311},"  timestamp: z.",[294,5367,2581],{"class":1112},[294,5369,5229],{"class":311},[294,5371,5372],{"class":1112},"datetime",[294,5374,4299],{"class":311},[294,5376,5377],{"class":296,"line":451},[294,5378,1258],{"class":311},[294,5380,5381],{"class":296,"line":459},[294,5382,366],{"emptyLinePlaceholder":365},[294,5384,5385,5388,5390,5392,5395,5397,5400,5402,5405],{"class":296,"line":467},[294,5386,5387],{"class":1195},"type",[294,5389,4034],{"class":1112},[294,5391,1223],{"class":1195},[294,5393,5394],{"class":1112}," z",[294,5396,4250],{"class":311},[294,5398,5399],{"class":1112},"infer",[294,5401,2078],{"class":311},[294,5403,5404],{"class":1195},"typeof",[294,5406,5407],{"class":311}," OrderEventSchema>;\n",[294,5409,5410],{"class":296,"line":475},[294,5411,366],{"emptyLinePlaceholder":365},[294,5413,5414,5417,5420,5422,5425,5427,5430,5432,5434,5436],{"class":296,"line":486},[294,5415,5416],{"class":1195},"function",[294,5418,5419],{"class":1112}," validateEvent",[294,5421,1270],{"class":311},[294,5423,5424],{"class":1376},"raw",[294,5426,2092],{"class":1195},[294,5428,5429],{"class":315}," unknown",[294,5431,2653],{"class":311},[294,5433,2092],{"class":1195},[294,5435,4034],{"class":1112},[294,5437,1282],{"class":311},[294,5439,5440,5442,5445,5447,5450,5453],{"class":296,"line":494},[294,5441,2671],{"class":1195},[294,5443,5444],{"class":315}," result",[294,5446,1223],{"class":1195},[294,5448,5449],{"class":311}," OrderEventSchema.",[294,5451,5452],{"class":1112},"safeParse",[294,5454,5455],{"class":311},"(raw);\n",[294,5457,5458],{"class":296,"line":502},[294,5459,366],{"emptyLinePlaceholder":365},[294,5461,5462,5465,5467,5469],{"class":296,"line":513},[294,5463,5464],{"class":1195},"  if",[294,5466,1568],{"class":311},[294,5468,3964],{"class":1195},[294,5470,5471],{"class":311},"result.success) {\n",[294,5473,5474],{"class":296,"line":521},[294,5475,5476],{"class":300},"    // Log validation errors for observability\n",[294,5478,5479,5482,5485,5487,5490],{"class":296,"line":529},[294,5480,5481],{"class":311},"    console.",[294,5483,5484],{"class":1112},"error",[294,5486,1270],{"class":311},[294,5488,5489],{"class":336},"'Schema validation failed:'",[294,5491,5492],{"class":311},", result.error.issues);\n",[294,5494,5495,5498,5500,5503],{"class":296,"line":537},[294,5496,5497],{"class":1195},"    throw",[294,5499,1226],{"class":1195},[294,5501,5502],{"class":1112}," SchemaValidationError",[294,5504,5505],{"class":311},"(result.error);\n",[294,5507,5508],{"class":296,"line":548},[294,5509,2298],{"class":311},[294,5511,5512],{"class":296,"line":556},[294,5513,366],{"emptyLinePlaceholder":365},[294,5515,5516,5518],{"class":296,"line":566},[294,5517,2757],{"class":1195},[294,5519,5520],{"class":311}," result.data;\n",[294,5522,5523],{"class":296,"line":573},[294,5524,2159],{"class":311},[79,5526,5528],{"id":5527},"dead-letter-queues","Dead-Letter Queues",[19,5530,5531],{},"Events that fail processing — due to schema violations, transformation errors, or downstream service failures — should never be silently dropped. Route them to a dead-letter queue (DLQ) for investigation and potential reprocessing. Your DLQ strategy should include:",[1711,5533,5534,5540,5546],{},[50,5535,5536,5539],{},[23,5537,5538],{},"Metadata enrichment",": Attach the original topic, partition, offset, error message, and timestamp to each dead-lettered event.",[50,5541,5542,5545],{},[23,5543,5544],{},"Alerting",": Trigger alerts when the DLQ depth exceeds a threshold. A growing DLQ indicates a systemic problem.",[50,5547,5548,5551],{},[23,5549,5550],{},"Reprocessing",": Build tooling to replay events from the DLQ back into the pipeline after the root cause is fixed.",[79,5553,5555],{"id":5554},"monitoring-and-alerting","Monitoring and Alerting",[19,5557,5558],{},"At minimum, monitor these metrics for every pipeline component:",[1711,5560,5561,5567,5573,5579,5585],{},[50,5562,5563,5566],{},[23,5564,5565],{},"Ingestion lag",": The delay between event production and consumption. Growing lag indicates your consumers cannot keep up.",[50,5568,5569,5572],{},[23,5570,5571],{},"Processing throughput",": Events processed per second. Track this alongside error rates to distinguish between slowdowns and failures.",[50,5574,5575,5578],{},[23,5576,5577],{},"Error rate",": Percentage of events that fail processing. Even a 0.1% error rate at 1 million events per day means 1,000 corrupted or lost records.",[50,5580,5581,5584],{},[23,5582,5583],{},"End-to-end latency",": The total time from event production to availability in the serving layer. This is the metric your business users care about.",[50,5586,5587,5590],{},[23,5588,5589],{},"Consumer group health",": Active consumers, partition assignments, rebalancing frequency. Frequent rebalances indicate instability.",[79,5592,5594],{"id":5593},"data-contracts","Data Contracts",[19,5596,5597],{},"Data contracts formalise the agreement between data producers and consumers. They define the schema, semantics, quality expectations, and SLAs for each data product. When a producer wants to change a field, they must evaluate the impact on downstream consumers first.",[19,5599,5600],{},"A practical data contract includes:",[1711,5602,5603,5609,5615,5621,5627],{},[50,5604,5605,5608],{},[23,5606,5607],{},"Schema definition"," (Avro, Protobuf, or JSON Schema)",[50,5610,5611,5614],{},[23,5612,5613],{},"Semantic descriptions"," for each field (what does \"total\" mean — before or after tax?)",[50,5616,5617,5620],{},[23,5618,5619],{},"Quality rules"," (e.g., \"customerId must not be null,\" \"total must equal the sum of item prices\")",[50,5622,5623,5626],{},[23,5624,5625],{},"SLAs"," (latency, availability, freshness guarantees)",[50,5628,5629,5632],{},[23,5630,5631],{},"Ownership"," (which team owns this data product and is responsible for its quality)",[14,5634,5636],{"id":5635},"common-pitfalls-in-real-time-pipeline-design","Common Pitfalls in Real-Time Pipeline Design",[19,5638,5639,5640,5643],{},"Building real-time data pipelines is more complex than batch processing, and the failure modes are different. These are the pitfalls we see most often when working with clients on their ",[230,5641,5642],{"href":2015},"cloud-native"," data infrastructure.",[79,5645,5647],{"id":5646},"over-engineering-from-day-one","Over-Engineering from Day One",[19,5649,5650],{},"Not every use case needs Kafka, Flink, and a data lakehouse. If you are processing 100 events per minute, a simple queue (SQS, Cloud Tasks) with a consumer writing to PostgreSQL may be perfectly adequate. Start with the simplest architecture that meets your current requirements and add complexity only when you have the traffic, the use cases, and the team to justify it.",[79,5652,5654],{"id":5653},"ignoring-backpressure","Ignoring Backpressure",[19,5656,5657],{},"When producers generate events faster than consumers can process them, unhandled backpressure leads to cascading failures. Your pipeline must have a strategy for this scenario: buffering in Kafka (which handles backpressure naturally through its log-based design), rate limiting at the ingestion layer, or scaling consumers automatically based on lag metrics.",[79,5659,5661],{"id":5660},"schema-evolution-nightmares","Schema Evolution Nightmares",[19,5663,5664],{},"In a batch system, you can update a schema and reprocess the entire dataset. In a streaming system, old and new events coexist in the same topic, and consumers must handle both formats. Plan for schema evolution from the start:",[1711,5666,5667,5670,5673,5680],{},[50,5668,5669],{},"Use a schema registry with compatibility checks (backward, forward, or full compatibility).",[50,5671,5672],{},"Design schemas with optional fields and sensible defaults.",[50,5674,5675,5676,5679],{},"Version your events explicitly (include a ",[291,5677,5678],{},"schemaVersion"," header or field).",[50,5681,5682],{},"Test consumer compatibility with both old and new schemas before deploying changes.",[79,5684,5686],{"id":5685},"cost-overruns","Cost Overruns",[19,5688,5689],{},"Real-time pipelines can become expensive quickly if not managed carefully. Common cost traps include:",[1711,5691,5692,5698,5704,5710],{},[50,5693,5694,5697],{},[23,5695,5696],{},"Over-provisioned Kafka clusters",": Right-size your brokers based on actual throughput, not peak theoretical capacity.",[50,5699,5700,5703],{},[23,5701,5702],{},"Unbounded retention",": Storing every event forever is expensive. Define retention policies based on business requirements and use tiered storage to move older data to cheaper storage automatically.",[50,5705,5706,5709],{},[23,5707,5708],{},"Unoptimised queries",": An OLAP query that scans a terabyte of data every 30 seconds for a dashboard refresh will generate a massive bill. Pre-aggregate data at the processing layer to reduce query costs.",[50,5711,5712,5715],{},[23,5713,5714],{},"Idle compute",": Stream processing clusters that are provisioned for peak load but sit idle most of the time. Use autoscaling where supported, or consider serverless alternatives for variable workloads.",[79,5717,5719],{"id":5718},"not-planning-for-failure","Not Planning for Failure",[19,5721,5722],{},"Every component in your pipeline will fail at some point. Design for it:",[1711,5724,5725,5731,5737,5743],{},[50,5726,5727,5730],{},[23,5728,5729],{},"Producer failures",": Use durable queues with acknowledgements so events are not lost when a producer crashes.",[50,5732,5733,5736],{},[23,5734,5735],{},"Consumer failures",": Implement checkpointing so consumers resume from where they left off, not from the beginning of the topic.",[50,5738,5739,5742],{},[23,5740,5741],{},"Processing failures",": Dead-letter queues, retry policies with exponential backoff, and circuit breakers for external service calls.",[50,5744,5745,5748],{},[23,5746,5747],{},"Storage failures",": Replication, backups, and the ability to rebuild derived data from the raw event log.",[1162,5750,5751],{"type":322},[19,5752,5753],{},"The event log (Kafka topic) should be your source of truth. If you can replay events from the log through your processing pipeline, you can rebuild any derived dataset. This makes your pipeline resilient to failures and enables you to evolve your processing logic without losing historical data.",[14,5755,5757],{"id":5756},"a-reference-architecture","A Reference Architecture",[19,5759,5760],{},"Putting it all together, here is a reference architecture for a real-time data pipeline that balances capability with operational simplicity:",[19,5762,5763,5766,5767,5769,5770,5773],{},[23,5764,5765],{},"Sources"," (application databases, APIs, IoT sensors, user events) produce events to ",[23,5768,3844],{}," (or a managed equivalent), which serves as the durable, ordered event log. ",[23,5771,5772],{},"Stream processors"," (Flink, custom consumers, or Kafka Streams) consume events, validate schemas, apply transformations, and enrich data with context from reference databases.",[19,5775,5776],{},"Processed events flow to multiple destinations based on use case:",[1711,5778,5779,5786,5792,5799],{},[50,5780,5781,5782,5785],{},"A ",[23,5783,5784],{},"data lakehouse"," (Databricks, Iceberg) for historical analytics and ML training.",[50,5787,5781,5788,5791],{},[23,5789,5790],{},"time-series database"," (TimescaleDB) for operational metrics and monitoring.",[50,5793,5794,5795,5798],{},"An ",[23,5796,5797],{},"OLAP engine"," (ClickHouse) for powering real-time dashboards.",[50,5800,5794,5801,5804],{},[23,5802,5803],{},"operational database"," (PostgreSQL, Redis) for serving data to applications.",[19,5806,5794,5807,5810],{},[23,5808,5809],{},"orchestration layer"," (Airflow, Dagster) manages batch processing jobs that complement the streaming pipeline — model training, data quality checks, backfills, and periodic aggregations.",[19,5812,5794,5813,5816],{},[23,5814,5815],{},"observability layer"," (Prometheus, Grafana, PagerDuty) monitors the health of every component and alerts on anomalies.",[19,5818,5819],{},"This architecture follows the principle of \"stream first, batch second\": events are processed in real time by default, and batch jobs are used only for workloads that genuinely require them.",[14,5821,5823],{"id":5822},"getting-started-a-practical-path","Getting Started: A Practical Path",[19,5825,5826],{},"If you are building your first real-time data pipeline, start small and iterate.",[19,5828,5829,5832],{},[23,5830,5831],{},"Week 1-2",": Identify a single, high-value use case. Fraud detection, real-time inventory updates, and live dashboards are common starting points. Define your latency requirements, expected event volume, and success criteria.",[19,5834,5835,5838],{},[23,5836,5837],{},"Week 3-4",": Build the ingestion layer. Set up a Kafka cluster (or managed equivalent) and write producers for your source systems. Verify that events are flowing correctly with the right schema and ordering.",[19,5840,5841,5844],{},[23,5842,5843],{},"Week 5-6",": Build the processing layer. Start with simple transformations — filtering, mapping, basic enrichment. Add complexity incrementally as your understanding of the data deepens.",[19,5846,5847,5850],{},[23,5848,5849],{},"Week 7-8",": Build the storage and serving layers. Connect your processed events to a database, dashboard, or API. Put the pipeline in front of real users and gather feedback.",[19,5852,5853,5856],{},[23,5854,5855],{},"Ongoing",": Add observability, schema validation, dead-letter queues, and data contracts. Optimise for cost and performance. Expand to additional use cases.",[14,5858,5860],{"id":5859},"build-your-modern-data-platform-with-cnex","Build Your Modern Data Platform with CNEX",[19,5862,5863],{},"Real-time data pipelines are a significant engineering investment, but they unlock capabilities that batch processing simply cannot provide — from fraud detection that catches threats in seconds to dashboards that reflect the current state of your business, not yesterday's state.",[19,5865,5866,5867,5870,5871,5874,5875,5878],{},"Our ",[230,5868,5869],{"href":3649},"data engineering team"," specialises in designing and implementing data pipelines on ",[230,5872,5873],{"href":2015},"cloud-native infrastructure",", with robust ",[230,5876,5877],{"href":232},"API integrations"," that connect your entire technology ecosystem. Whether you need a focused streaming pipeline for a single use case or a comprehensive data platform that supports real-time analytics, machine learning, and operational intelligence, we can help you build it right.",[19,5880,5881,5884,5885,5888],{},[23,5882,5883],{},"Ready to build a modern data platform?"," ",[230,5886,5887],{"href":2366},"Talk to our data engineering team"," and let us design a pipeline architecture that delivers the insights your business needs — when it needs them.",[2370,5890,5891],{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":289,"searchDepth":304,"depth":304,"links":5893},[5894,5895,5896,5902,5906,5912,5919,5920,5921],{"id":3636,"depth":304,"text":3637},{"id":3654,"depth":304,"text":3655},{"id":3828,"depth":304,"text":3829,"children":5897},[5898,5899,5900,5901],{"id":3835,"depth":319,"text":3836},{"id":4753,"depth":319,"text":4754},{"id":4807,"depth":319,"text":4808},{"id":4838,"depth":319,"text":4839},{"id":4873,"depth":304,"text":4874,"children":5903},[5904,5905],{"id":4880,"depth":319,"text":4881},{"id":5026,"depth":319,"text":5027},{"id":5163,"depth":304,"text":5164,"children":5907},[5908,5909,5910,5911],{"id":5170,"depth":319,"text":5171},{"id":5527,"depth":319,"text":5528},{"id":5554,"depth":319,"text":5555},{"id":5593,"depth":319,"text":5594},{"id":5635,"depth":304,"text":5636,"children":5913},[5914,5915,5916,5917,5918],{"id":5646,"depth":319,"text":5647},{"id":5653,"depth":319,"text":5654},{"id":5660,"depth":319,"text":5661},{"id":5685,"depth":319,"text":5686},{"id":5718,"depth":319,"text":5719},{"id":5756,"depth":304,"text":5757},{"id":5822,"depth":304,"text":5823},{"id":5859,"depth":304,"text":5860},"Cloud","2026-01-31","A technical guide to designing data pipelines that process, transform, and deliver insights in real time — from ingestion to dashboard.",{},"/blog/real-time-data-pipeline-guide",{"title":3628,"description":5924},"blog/real-time-data-pipeline-guide",[5930,5931,5932,5933],"Data Engineering","Analytics","Real-Time Processing","ETL","pbtus4umh6ZFXHGzRjoF4R8wfhBqwE7dy2ORTQkXCg0",[5936,7726,8649],{"id":5,"title":6,"author":5937,"body":5938,"category":2406,"coverImage":2407,"date":2408,"description":2409,"extension":2410,"featured":2411,"meta":7723,"navigation":365,"path":2413,"readingTime":2414,"seo":7724,"stem":2416,"tags":7725,"__hash__":2421},{"name":8,"role":9},{"type":11,"value":5939,"toc":7690},[5940,5942,5946,5948,5952,5954,5956,5958,5972,5974,5976,5978,5980,5984,5988,5990,5994,5998,6000,6004,6008,6070,6072,6074,6076,6078,6082,6084,6086,6088,6092,6096,6098,6100,6102,6104,6106,6108,6720,6722,6724,6726,6772,6774,6780,6782,6784,7176,7178,7180,7182,7190,7196,7202,7204,7214,7216,7218,7374,7376,7390,7394,7396,7398,7400,7430,7434,7436,7438,7440,7442,7444,7452,7454,7456,7544,7546,7548,7552,7554,7558,7646,7648,7650,7652,7674,7676,7680,7682,7688],[14,5941,17],{"id":16},[19,5943,21,5944,26],{},[23,5945,25],{},[19,5947,29],{},[31,5949,5950],{},[19,5951,35],{},[14,5953,39],{"id":38},[19,5955,42],{},[19,5957,45],{},[47,5959,5960,5962,5964,5966,5968,5970],{},[50,5961,52],{},[50,5963,55],{},[50,5965,58],{},[50,5967,61],{},[50,5969,64],{},[50,5971,67],{},[19,5973,70],{},[14,5975,74],{"id":73},[19,5977,77],{},[79,5979,82],{"id":81},[19,5981,5982,88],{},[23,5983,87],{},[19,5985,5986,94],{},[23,5987,93],{},[79,5989,98],{"id":97},[19,5991,5992,103],{},[23,5993,87],{},[19,5995,5996,108],{},[23,5997,93],{},[79,5999,112],{"id":111},[19,6001,6002,117],{},[23,6003,87],{},[19,6005,6006,122],{},[23,6007,93],{},[124,6009,6010,6020],{},[127,6011,6012],{},[130,6013,6014,6016,6018],{},[133,6015,135],{},[133,6017,138],{},[133,6019,141],{},[143,6021,6022,6030,6038,6046,6054,6062],{},[130,6023,6024,6026,6028],{},[148,6025,150],{},[148,6027,153],{},[148,6029,156],{},[130,6031,6032,6034,6036],{},[148,6033,161],{},[148,6035,164],{},[148,6037,167],{},[130,6039,6040,6042,6044],{},[148,6041,172],{},[148,6043,175],{},[148,6045,178],{},[130,6047,6048,6050,6052],{},[148,6049,183],{},[148,6051,186],{},[148,6053,189],{},[130,6055,6056,6058,6060],{},[148,6057,194],{},[148,6059,197],{},[148,6061,200],{},[130,6063,6064,6066,6068],{},[148,6065,205],{},[148,6067,208],{},[148,6069,211],{},[14,6071,215],{"id":214},[19,6073,218],{},[79,6075,222],{"id":221},[19,6077,225],{},[19,6079,228,6080,234],{},[230,6081,233],{"href":232},[79,6083,238],{"id":237},[19,6085,241],{},[79,6087,245],{"id":244},[19,6089,248,6090,253],{},[230,6091,252],{"href":251},[19,6093,256,6094,261],{},[230,6095,260],{"href":259},[79,6097,265],{"id":264},[19,6099,268],{},[14,6101,272],{"id":271},[19,6103,275],{},[79,6105,279],{"id":278},[19,6107,282],{},[284,6109,6110],{"className":286,"code":287,"language":288,"meta":289,"style":289},[291,6111,6112,6116,6124,6130,6138,6146,6154,6158,6164,6170,6176,6184,6192,6198,6204,6210,6218,6224,6230,6236,6244,6250,6256,6264,6270,6276,6282,6290,6296,6304,6310,6316,6322,6330,6336,6344,6350,6356,6362,6370,6374,6380,6386,6392,6400,6406,6412,6418,6424,6430,6436,6442,6450,6456,6462,6468,6474,6480,6488,6496,6504,6510,6518,6526,6534,6540,6548,6556,6562,6570,6578,6582,6588,6596,6602,6608,6616,6624,6630,6638,6644,6650,6656,6662,6668,6676,6682,6690,6698,6704,6712],{"__ignoreMap":289},[294,6113,6114],{"class":296,"line":297},[294,6115,301],{"class":300},[294,6117,6118,6120,6122],{"class":296,"line":304},[294,6119,308],{"class":307},[294,6121,312],{"class":311},[294,6123,316],{"class":315},[294,6125,6126,6128],{"class":296,"line":319},[294,6127,322],{"class":307},[294,6129,325],{"class":311},[294,6131,6132,6134,6136],{"class":296,"line":328},[294,6133,331],{"class":307},[294,6135,312],{"class":311},[294,6137,337],{"class":336},[294,6139,6140,6142,6144],{"class":296,"line":340},[294,6141,343],{"class":307},[294,6143,312],{"class":311},[294,6145,348],{"class":315},[294,6147,6148,6150,6152],{"class":296,"line":351},[294,6149,354],{"class":307},[294,6151,312],{"class":311},[294,6153,359],{"class":336},[294,6155,6156],{"class":296,"line":362},[294,6157,366],{"emptyLinePlaceholder":365},[294,6159,6160,6162],{"class":296,"line":369},[294,6161,372],{"class":307},[294,6163,325],{"class":311},[294,6165,6166,6168],{"class":296,"line":377},[294,6167,380],{"class":307},[294,6169,325],{"class":311},[294,6171,6172,6174],{"class":296,"line":385},[294,6173,388],{"class":307},[294,6175,325],{"class":311},[294,6177,6178,6180,6182],{"class":296,"line":393},[294,6179,396],{"class":307},[294,6181,312],{"class":311},[294,6183,401],{"class":336},[294,6185,6186,6188,6190],{"class":296,"line":404},[294,6187,407],{"class":307},[294,6189,312],{"class":311},[294,6191,412],{"class":336},[294,6193,6194,6196],{"class":296,"line":415},[294,6195,418],{"class":307},[294,6197,325],{"class":311},[294,6199,6200,6202],{"class":296,"line":423},[294,6201,426],{"class":311},[294,6203,429],{"class":336},[294,6205,6206,6208],{"class":296,"line":432},[294,6207,435],{"class":307},[294,6209,325],{"class":311},[294,6211,6212,6214,6216],{"class":296,"line":440},[294,6213,443],{"class":307},[294,6215,312],{"class":311},[294,6217,448],{"class":315},[294,6219,6220,6222],{"class":296,"line":451},[294,6221,454],{"class":307},[294,6223,325],{"class":311},[294,6225,6226,6228],{"class":296,"line":459},[294,6227,462],{"class":307},[294,6229,325],{"class":311},[294,6231,6232,6234],{"class":296,"line":467},[294,6233,470],{"class":307},[294,6235,325],{"class":311},[294,6237,6238,6240,6242],{"class":296,"line":475},[294,6239,478],{"class":307},[294,6241,312],{"class":311},[294,6243,483],{"class":336},[294,6245,6246,6248],{"class":296,"line":486},[294,6247,489],{"class":307},[294,6249,325],{"class":311},[294,6251,6252,6254],{"class":296,"line":494},[294,6253,497],{"class":336},[294,6255,325],{"class":311},[294,6257,6258,6260,6262],{"class":296,"line":502},[294,6259,505],{"class":307},[294,6261,312],{"class":311},[294,6263,510],{"class":336},[294,6265,6266,6268],{"class":296,"line":513},[294,6267,516],{"class":307},[294,6269,325],{"class":311},[294,6271,6272,6274],{"class":296,"line":521},[294,6273,524],{"class":307},[294,6275,325],{"class":311},[294,6277,6278,6280],{"class":296,"line":529},[294,6279,532],{"class":307},[294,6281,325],{"class":311},[294,6283,6284,6286,6288],{"class":296,"line":537},[294,6285,540],{"class":307},[294,6287,312],{"class":311},[294,6289,545],{"class":336},[294,6291,6292,6294],{"class":296,"line":548},[294,6293,551],{"class":336},[294,6295,325],{"class":311},[294,6297,6298,6300,6302],{"class":296,"line":556},[294,6299,505],{"class":307},[294,6301,312],{"class":311},[294,6303,563],{"class":336},[294,6305,6306,6308],{"class":296,"line":566},[294,6307,516],{"class":307},[294,6309,325],{"class":311},[294,6311,6312,6314],{"class":296,"line":573},[294,6313,524],{"class":307},[294,6315,325],{"class":311},[294,6317,6318,6320],{"class":296,"line":580},[294,6319,532],{"class":307},[294,6321,325],{"class":311},[294,6323,6324,6326,6328],{"class":296,"line":587},[294,6325,540],{"class":307},[294,6327,312],{"class":311},[294,6329,594],{"class":336},[294,6331,6332,6334],{"class":296,"line":597},[294,6333,600],{"class":336},[294,6335,325],{"class":311},[294,6337,6338,6340,6342],{"class":296,"line":605},[294,6339,505],{"class":307},[294,6341,312],{"class":311},[294,6343,612],{"class":336},[294,6345,6346,6348],{"class":296,"line":615},[294,6347,516],{"class":307},[294,6349,325],{"class":311},[294,6351,6352,6354],{"class":296,"line":622},[294,6353,524],{"class":307},[294,6355,325],{"class":311},[294,6357,6358,6360],{"class":296,"line":629},[294,6359,532],{"class":307},[294,6361,325],{"class":311},[294,6363,6364,6366,6368],{"class":296,"line":636},[294,6365,540],{"class":307},[294,6367,312],{"class":311},[294,6369,643],{"class":336},[294,6371,6372],{"class":296,"line":646},[294,6373,366],{"emptyLinePlaceholder":365},[294,6375,6376,6378],{"class":296,"line":651},[294,6377,654],{"class":307},[294,6379,325],{"class":311},[294,6381,6382,6384],{"class":296,"line":659},[294,6383,662],{"class":307},[294,6385,325],{"class":311},[294,6387,6388,6390],{"class":296,"line":667},[294,6389,670],{"class":307},[294,6391,325],{"class":311},[294,6393,6394,6396,6398],{"class":296,"line":675},[294,6395,678],{"class":307},[294,6397,312],{"class":311},[294,6399,683],{"class":336},[294,6401,6402,6404],{"class":296,"line":686},[294,6403,689],{"class":307},[294,6405,325],{"class":311},[294,6407,6408,6410],{"class":296,"line":694},[294,6409,426],{"class":311},[294,6411,699],{"class":336},[294,6413,6414,6416],{"class":296,"line":702},[294,6415,426],{"class":311},[294,6417,707],{"class":336},[294,6419,6420,6422],{"class":296,"line":710},[294,6421,426],{"class":311},[294,6423,715],{"class":336},[294,6425,6426,6428],{"class":296,"line":718},[294,6427,426],{"class":311},[294,6429,723],{"class":336},[294,6431,6432,6434],{"class":296,"line":726},[294,6433,729],{"class":307},[294,6435,325],{"class":311},[294,6437,6438,6440],{"class":296,"line":734},[294,6439,737],{"class":307},[294,6441,325],{"class":311},[294,6443,6444,6446,6448],{"class":296,"line":742},[294,6445,745],{"class":307},[294,6447,312],{"class":311},[294,6449,750],{"class":336},[294,6451,6452,6454],{"class":296,"line":753},[294,6453,756],{"class":307},[294,6455,325],{"class":311},[294,6457,6458,6460],{"class":296,"line":761},[294,6459,764],{"class":311},[294,6461,767],{"class":336},[294,6463,6464,6466],{"class":296,"line":770},[294,6465,764],{"class":311},[294,6467,775],{"class":336},[294,6469,6470,6472],{"class":296,"line":778},[294,6471,764],{"class":311},[294,6473,783],{"class":336},[294,6475,6476,6478],{"class":296,"line":786},[294,6477,789],{"class":307},[294,6479,325],{"class":311},[294,6481,6482,6484,6486],{"class":296,"line":794},[294,6483,745],{"class":307},[294,6485,312],{"class":311},[294,6487,750],{"class":336},[294,6489,6490,6492,6494],{"class":296,"line":803},[294,6491,806],{"class":307},[294,6493,312],{"class":311},[294,6495,811],{"class":336},[294,6497,6498,6500,6502],{"class":296,"line":814},[294,6499,505],{"class":307},[294,6501,312],{"class":311},[294,6503,821],{"class":336},[294,6505,6506,6508],{"class":296,"line":824},[294,6507,827],{"class":307},[294,6509,325],{"class":311},[294,6511,6512,6514,6516],{"class":296,"line":832},[294,6513,745],{"class":307},[294,6515,312],{"class":311},[294,6517,750],{"class":336},[294,6519,6520,6522,6524],{"class":296,"line":841},[294,6521,844],{"class":307},[294,6523,312],{"class":311},[294,6525,849],{"class":315},[294,6527,6528,6530,6532],{"class":296,"line":852},[294,6529,855],{"class":307},[294,6531,312],{"class":311},[294,6533,860],{"class":315},[294,6535,6536,6538],{"class":296,"line":863},[294,6537,866],{"class":307},[294,6539,325],{"class":311},[294,6541,6542,6544,6546],{"class":296,"line":871},[294,6543,745],{"class":307},[294,6545,312],{"class":311},[294,6547,750],{"class":336},[294,6549,6550,6552,6554],{"class":296,"line":880},[294,6551,806],{"class":307},[294,6553,312],{"class":311},[294,6555,887],{"class":336},[294,6557,6558,6560],{"class":296,"line":890},[294,6559,893],{"class":307},[294,6561,325],{"class":311},[294,6563,6564,6566,6568],{"class":296,"line":898},[294,6565,745],{"class":307},[294,6567,312],{"class":311},[294,6569,750],{"class":336},[294,6571,6572,6574,6576],{"class":296,"line":907},[294,6573,855],{"class":307},[294,6575,312],{"class":311},[294,6577,914],{"class":315},[294,6579,6580],{"class":296,"line":917},[294,6581,366],{"emptyLinePlaceholder":365},[294,6583,6584,6586],{"class":296,"line":922},[294,6585,925],{"class":307},[294,6587,325],{"class":311},[294,6589,6590,6592,6594],{"class":296,"line":930},[294,6591,678],{"class":307},[294,6593,312],{"class":311},[294,6595,683],{"class":336},[294,6597,6598,6600],{"class":296,"line":939},[294,6599,729],{"class":307},[294,6601,325],{"class":311},[294,6603,6604,6606],{"class":296,"line":946},[294,6605,949],{"class":307},[294,6607,325],{"class":311},[294,6609,6610,6612,6614],{"class":296,"line":954},[294,6611,745],{"class":307},[294,6613,312],{"class":311},[294,6615,750],{"class":336},[294,6617,6618,6620,6622],{"class":296,"line":963},[294,6619,806],{"class":307},[294,6621,312],{"class":311},[294,6623,970],{"class":336},[294,6625,6626,6628],{"class":296,"line":973},[294,6627,976],{"class":307},[294,6629,325],{"class":311},[294,6631,6632,6634,6636],{"class":296,"line":981},[294,6633,745],{"class":307},[294,6635,312],{"class":311},[294,6637,750],{"class":336},[294,6639,6640,6642],{"class":296,"line":990},[294,6641,756],{"class":307},[294,6643,325],{"class":311},[294,6645,6646,6648],{"class":296,"line":997},[294,6647,764],{"class":311},[294,6649,1002],{"class":336},[294,6651,6652,6654],{"class":296,"line":1005},[294,6653,764],{"class":311},[294,6655,1010],{"class":336},[294,6657,6658,6660],{"class":296,"line":1013},[294,6659,764],{"class":311},[294,6661,1018],{"class":336},[294,6663,6664,6666],{"class":296,"line":1021},[294,6665,737],{"class":307},[294,6667,325],{"class":311},[294,6669,6670,6672,6674],{"class":296,"line":1028},[294,6671,745],{"class":307},[294,6673,312],{"class":311},[294,6675,750],{"class":336},[294,6677,6678,6680],{"class":296,"line":1037},[294,6679,789],{"class":307},[294,6681,325],{"class":311},[294,6683,6684,6686,6688],{"class":296,"line":1044},[294,6685,745],{"class":307},[294,6687,312],{"class":311},[294,6689,750],{"class":336},[294,6691,6692,6694,6696],{"class":296,"line":1053},[294,6693,806],{"class":307},[294,6695,312],{"class":311},[294,6697,811],{"class":336},[294,6699,6700,6702],{"class":296,"line":1062},[294,6701,1065],{"class":307},[294,6703,325],{"class":311},[294,6705,6706,6708,6710],{"class":296,"line":1070},[294,6707,745],{"class":307},[294,6709,312],{"class":311},[294,6711,750],{"class":336},[294,6713,6714,6716,6718],{"class":296,"line":1079},[294,6715,806],{"class":307},[294,6717,312],{"class":311},[294,6719,811],{"class":336},[19,6721,1088],{},[79,6723,1092],{"id":1091},[19,6725,1095],{},[284,6727,6728],{"className":1098,"code":1099,"language":1100,"meta":289,"style":289},[291,6729,6730,6734,6748,6752,6756,6760],{"__ignoreMap":289},[294,6731,6732],{"class":296,"line":297},[294,6733,1107],{"class":300},[294,6735,6736,6738,6740,6742,6744,6746],{"class":296,"line":304},[294,6737,1113],{"class":1112},[294,6739,1116],{"class":336},[294,6741,1119],{"class":336},[294,6743,1122],{"class":336},[294,6745,1125],{"class":315},[294,6747,1128],{"class":315},[294,6749,6750],{"class":296,"line":319},[294,6751,366],{"emptyLinePlaceholder":365},[294,6753,6754],{"class":296,"line":328},[294,6755,1137],{"class":300},[294,6757,6758],{"class":296,"line":340},[294,6759,1142],{"class":300},[294,6761,6762,6764,6766,6768,6770],{"class":296,"line":351},[294,6763,1113],{"class":1112},[294,6765,1149],{"class":336},[294,6767,1122],{"class":336},[294,6769,1154],{"class":315},[294,6771,1157],{"class":336},[19,6773,1160],{},[1162,6775,6776],{"type":1164},[19,6777,1167,6778,1171],{},[291,6779,1170],{},[79,6781,1175],{"id":1174},[19,6783,1178],{},[284,6785,6786],{"className":1181,"code":1182,"language":1183,"meta":289,"style":289},[291,6787,6788,6792,6804,6808,6822,6830,6838,6842,6846,6860,6878,6884,6892,6904,6916,6940,6944,6960,6968,6976,6984,6992,7000,7004,7008,7028,7036,7048,7056,7064,7072,7076,7080,7100,7114,7122,7130,7138,7146,7150,7164,7168,7172],{"__ignoreMap":289},[294,6789,6790],{"class":296,"line":297},[294,6791,1190],{"class":300},[294,6793,6794,6796,6798,6800,6802],{"class":296,"line":304},[294,6795,1196],{"class":1195},[294,6797,1199],{"class":311},[294,6799,1202],{"class":1195},[294,6801,1205],{"class":336},[294,6803,1208],{"class":311},[294,6805,6806],{"class":296,"line":319},[294,6807,366],{"emptyLinePlaceholder":365},[294,6809,6810,6812,6814,6816,6818,6820],{"class":296,"line":328},[294,6811,1217],{"class":1195},[294,6813,1220],{"class":315},[294,6815,1223],{"class":1195},[294,6817,1226],{"class":1195},[294,6819,1229],{"class":1112},[294,6821,1232],{"class":311},[294,6823,6824,6826,6828],{"class":296,"line":340},[294,6825,1237],{"class":311},[294,6827,1240],{"class":336},[294,6829,1243],{"class":311},[294,6831,6832,6834,6836],{"class":296,"line":351},[294,6833,1248],{"class":311},[294,6835,1251],{"class":336},[294,6837,1243],{"class":311},[294,6839,6840],{"class":296,"line":362},[294,6841,1258],{"class":311},[294,6843,6844],{"class":296,"line":369},[294,6845,366],{"emptyLinePlaceholder":365},[294,6847,6848,6850,6852,6854,6856,6858],{"class":296,"line":377},[294,6849,1267],{"class":1112},[294,6851,1270],{"class":311},[294,6853,1273],{"class":336},[294,6855,1276],{"class":311},[294,6857,1279],{"class":1195},[294,6859,1282],{"class":311},[294,6861,6862,6864,6866,6868,6870,6872,6874,6876],{"class":296,"line":385},[294,6863,1287],{"class":1112},[294,6865,1270],{"class":311},[294,6867,1292],{"class":336},[294,6869,1295],{"class":311},[294,6871,1298],{"class":1195},[294,6873,1301],{"class":311},[294,6875,1279],{"class":1195},[294,6877,1282],{"class":311},[294,6879,6880,6882],{"class":296,"line":393},[294,6881,1310],{"class":1195},[294,6883,1313],{"class":311},[294,6885,6886,6888,6890],{"class":296,"line":404},[294,6887,1318],{"class":311},[294,6889,1321],{"class":1112},[294,6891,1324],{"class":311},[294,6893,6894,6896,6898,6900,6902],{"class":296,"line":415},[294,6895,1318],{"class":311},[294,6897,1331],{"class":1112},[294,6899,1270],{"class":311},[294,6901,1336],{"class":336},[294,6903,1339],{"class":311},[294,6905,6906,6908,6910,6912,6914],{"class":296,"line":423},[294,6907,1318],{"class":311},[294,6909,1346],{"class":1112},[294,6911,1270],{"class":311},[294,6913,1351],{"class":336},[294,6915,1339],{"class":311},[294,6917,6918,6920,6922,6924,6926,6928,6930,6932,6934,6936,6938],{"class":296,"line":432},[294,6919,1318],{"class":311},[294,6921,1360],{"class":1112},[294,6923,1270],{"class":311},[294,6925,1365],{"class":336},[294,6927,1295],{"class":311},[294,6929,1370],{"class":336},[294,6931,1373],{"class":311},[294,6933,1377],{"class":1376},[294,6935,1380],{"class":311},[294,6937,1279],{"class":1195},[294,6939,1282],{"class":311},[294,6941,6942],{"class":296,"line":440},[294,6943,1389],{"class":311},[294,6945,6946,6948,6950,6952,6954,6956,6958],{"class":296,"line":451},[294,6947,1394],{"class":311},[294,6949,1397],{"class":1112},[294,6951,1400],{"class":311},[294,6953,1403],{"class":336},[294,6955,312],{"class":311},[294,6957,1408],{"class":336},[294,6959,1411],{"class":311},[294,6961,6962,6964,6966],{"class":296,"line":459},[294,6963,1394],{"class":311},[294,6965,1418],{"class":1112},[294,6967,1232],{"class":311},[294,6969,6970,6972,6974],{"class":296,"line":467},[294,6971,1425],{"class":311},[294,6973,1428],{"class":336},[294,6975,1243],{"class":311},[294,6977,6978,6980,6982],{"class":296,"line":475},[294,6979,1435],{"class":311},[294,6981,1438],{"class":336},[294,6983,1243],{"class":311},[294,6985,6986,6988,6990],{"class":296,"line":486},[294,6987,1445],{"class":311},[294,6989,1448],{"class":336},[294,6991,1243],{"class":311},[294,6993,6994,6996,6998],{"class":296,"line":494},[294,6995,1455],{"class":311},[294,6997,1458],{"class":336},[294,6999,1243],{"class":311},[294,7001,7002],{"class":296,"line":502},[294,7003,1465],{"class":311},[294,7005,7006],{"class":296,"line":513},[294,7007,1470],{"class":311},[294,7009,7010,7012,7014,7016,7018,7020,7022,7024,7026],{"class":296,"line":521},[294,7011,1318],{"class":311},[294,7013,1477],{"class":1112},[294,7015,1270],{"class":311},[294,7017,1482],{"class":315},[294,7019,1373],{"class":311},[294,7021,1377],{"class":1376},[294,7023,1380],{"class":311},[294,7025,1279],{"class":1195},[294,7027,1282],{"class":311},[294,7029,7030,7032,7034],{"class":296,"line":529},[294,7031,1497],{"class":311},[294,7033,1418],{"class":1112},[294,7035,1232],{"class":311},[294,7037,7038,7040,7042,7044,7046],{"class":296,"line":537},[294,7039,1506],{"class":311},[294,7041,1509],{"class":1112},[294,7043,1270],{"class":311},[294,7045,1514],{"class":336},[294,7047,1517],{"class":311},[294,7049,7050,7052,7054],{"class":296,"line":548},[294,7051,1522],{"class":311},[294,7053,1525],{"class":336},[294,7055,1243],{"class":311},[294,7057,7058,7060,7062],{"class":296,"line":556},[294,7059,1532],{"class":311},[294,7061,1428],{"class":336},[294,7063,1243],{"class":311},[294,7065,7066,7068,7070],{"class":296,"line":566},[294,7067,1541],{"class":311},[294,7069,1438],{"class":336},[294,7071,1243],{"class":311},[294,7073,7074],{"class":296,"line":573},[294,7075,1550],{"class":311},[294,7077,7078],{"class":296,"line":580},[294,7079,1470],{"class":311},[294,7081,7082,7084,7086,7088,7090,7092,7094,7096,7098],{"class":296,"line":587},[294,7083,1318],{"class":311},[294,7085,1561],{"class":1112},[294,7087,1270],{"class":311},[294,7089,1298],{"class":1195},[294,7091,1568],{"class":311},[294,7093,1571],{"class":1376},[294,7095,1380],{"class":311},[294,7097,1279],{"class":1195},[294,7099,1282],{"class":311},[294,7101,7102,7104,7106,7108,7110,7112],{"class":296,"line":597},[294,7103,1582],{"class":1195},[294,7105,1585],{"class":315},[294,7107,1223],{"class":1195},[294,7109,1590],{"class":1195},[294,7111,1593],{"class":1112},[294,7113,1596],{"class":311},[294,7115,7116,7118,7120],{"class":296,"line":605},[294,7117,1532],{"class":311},[294,7119,1428],{"class":336},[294,7121,1243],{"class":311},[294,7123,7124,7126,7128],{"class":296,"line":615},[294,7125,1541],{"class":311},[294,7127,1438],{"class":336},[294,7129,1243],{"class":311},[294,7131,7132,7134,7136],{"class":296,"line":622},[294,7133,1617],{"class":311},[294,7135,1448],{"class":336},[294,7137,1243],{"class":311},[294,7139,7140,7142,7144],{"class":296,"line":629},[294,7141,1626],{"class":311},[294,7143,1458],{"class":336},[294,7145,1243],{"class":311},[294,7147,7148],{"class":296,"line":636},[294,7149,1550],{"class":311},[294,7151,7152,7154,7156,7158,7160,7162],{"class":296,"line":646},[294,7153,1639],{"class":1112},[294,7155,1642],{"class":311},[294,7157,1645],{"class":1112},[294,7159,1270],{"class":311},[294,7161,1525],{"class":336},[294,7163,1652],{"class":311},[294,7165,7166],{"class":296,"line":651},[294,7167,1657],{"class":311},[294,7169,7170],{"class":296,"line":659},[294,7171,1662],{"class":311},[294,7173,7174],{"class":296,"line":667},[294,7175,1258],{"class":311},[19,7177,1669],{},[79,7179,1673],{"id":1672},[19,7181,1676],{},[19,7183,7184,1568,7186,1295,7188,1688],{},[23,7185,1681],{},[291,7187,1684],{},[291,7189,1687],{},[19,7191,7192,1568,7194,1697],{},[23,7193,1693],{},[291,7195,1696],{},[19,7197,7198,1568,7200,1706],{},[23,7199,1702],{},[291,7201,1705],{},[19,7203,1709],{},[1711,7205,7206,7208,7210,7212],{},[50,7207,1715],{},[50,7209,1718],{},[50,7211,1721],{},[50,7213,1724],{},[79,7215,1728],{"id":1727},[19,7217,1731],{},[284,7219,7220],{"className":1181,"code":1734,"language":1183,"meta":289,"style":289},[291,7221,7222,7226,7238,7242,7254,7268,7278,7300,7318,7334,7342,7350,7362,7366,7370],{"__ignoreMap":289},[294,7223,7224],{"class":296,"line":297},[294,7225,1741],{"class":300},[294,7227,7228,7230,7232,7234,7236],{"class":296,"line":304},[294,7229,1196],{"class":1195},[294,7231,1748],{"class":311},[294,7233,1202],{"class":1195},[294,7235,1753],{"class":336},[294,7237,1208],{"class":311},[294,7239,7240],{"class":296,"line":319},[294,7241,366],{"emptyLinePlaceholder":365},[294,7243,7244,7246,7248,7250,7252],{"class":296,"line":328},[294,7245,1217],{"class":1195},[294,7247,1766],{"class":315},[294,7249,1223],{"class":1195},[294,7251,1771],{"class":1112},[294,7253,1232],{"class":311},[294,7255,7256,7258,7260,7262,7264,7266],{"class":296,"line":340},[294,7257,1778],{"class":311},[294,7259,1781],{"class":315},[294,7261,1784],{"class":1195},[294,7263,1787],{"class":315},[294,7265,1295],{"class":311},[294,7267,1792],{"class":300},[294,7269,7270,7272,7274,7276],{"class":296,"line":351},[294,7271,1797],{"class":311},[294,7273,1800],{"class":315},[294,7275,1803],{"class":311},[294,7277,1806],{"class":300},[294,7279,7280,7282,7284,7286,7288,7290,7292,7294,7296,7298],{"class":296,"line":362},[294,7281,1811],{"class":1112},[294,7283,1814],{"class":311},[294,7285,1817],{"class":1376},[294,7287,1380],{"class":311},[294,7289,1279],{"class":1195},[294,7291,1824],{"class":311},[294,7293,1827],{"class":336},[294,7295,1830],{"class":311},[294,7297,1833],{"class":1195},[294,7299,1836],{"class":311},[294,7301,7302,7304,7306,7308,7310,7312,7314,7316],{"class":296,"line":369},[294,7303,1841],{"class":1112},[294,7305,1814],{"class":311},[294,7307,1817],{"class":1376},[294,7309,1295],{"class":311},[294,7311,1850],{"class":1376},[294,7313,1380],{"class":311},[294,7315,1279],{"class":1195},[294,7317,1282],{"class":311},[294,7319,7320,7322,7324,7326,7328,7330,7332],{"class":296,"line":377},[294,7321,1861],{"class":311},[294,7323,1864],{"class":1112},[294,7325,1270],{"class":311},[294,7327,1869],{"class":315},[294,7329,1872],{"class":311},[294,7331,1875],{"class":1112},[294,7333,1232],{"class":311},[294,7335,7336,7338,7340],{"class":296,"line":385},[294,7337,1882],{"class":311},[294,7339,1885],{"class":336},[294,7341,1243],{"class":311},[294,7343,7344,7346,7348],{"class":296,"line":393},[294,7345,1892],{"class":311},[294,7347,1895],{"class":336},[294,7349,1243],{"class":311},[294,7351,7352,7354,7356,7358,7360],{"class":296,"line":404},[294,7353,1902],{"class":311},[294,7355,1905],{"class":1112},[294,7357,1270],{"class":311},[294,7359,1910],{"class":336},[294,7361,1517],{"class":311},[294,7363,7364],{"class":296,"line":415},[294,7365,1917],{"class":311},[294,7367,7368],{"class":296,"line":423},[294,7369,1922],{"class":311},[294,7371,7372],{"class":296,"line":432},[294,7373,1258],{"class":311},[19,7375,1929],{},[1711,7377,7378,7382,7386],{},[50,7379,7380,1937],{},[23,7381,1936],{},[50,7383,7384,1943],{},[23,7385,1942],{},[50,7387,7388,1949],{},[23,7389,1948],{},[1162,7391,7392],{"type":322},[19,7393,1954],{},[14,7395,1958],{"id":1957},[19,7397,1961],{},[79,7399,1965],{"id":1964},[1711,7401,7402,7406,7410,7414,7418,7422,7426],{},[50,7403,7404,1973],{},[23,7405,1972],{},[50,7407,7408,1979],{},[23,7409,1978],{},[50,7411,7412,1985],{},[23,7413,1984],{},[50,7415,7416,1991],{},[23,7417,1990],{},[50,7419,7420,1997],{},[23,7421,1996],{},[50,7423,7424,2003],{},[23,7425,2002],{},[50,7427,7428,2009],{},[23,7429,2008],{},[19,7431,2012,7432,2017],{},[230,7433,2016],{"href":2015},[14,7435,2021],{"id":2020},[19,7437,2024],{},[79,7439,2028],{"id":2027},[19,7441,2031],{},[79,7443,2035],{"id":2034},[19,7445,2038,7446,2042,7448,2046,7450,2050],{},[291,7447,2041],{},[291,7449,2045],{},[291,7451,2049],{},[79,7453,2054],{"id":2053},[19,7455,2057],{},[284,7457,7458],{"className":1181,"code":2060,"language":1183,"meta":289,"style":289},[291,7459,7460,7464,7476,7486,7494,7508,7518,7528,7532,7536,7540],{"__ignoreMap":289},[294,7461,7462],{"class":296,"line":297},[294,7463,2067],{"class":300},[294,7465,7466,7468,7470,7472,7474],{"class":296,"line":304},[294,7467,2072],{"class":1195},[294,7469,2075],{"class":1112},[294,7471,2078],{"class":311},[294,7473,2081],{"class":1112},[294,7475,2084],{"class":311},[294,7477,7478,7480,7482,7484],{"class":296,"line":319},[294,7479,2089],{"class":1376},[294,7481,2092],{"class":1195},[294,7483,2095],{"class":1112},[294,7485,2098],{"class":311},[294,7487,7488,7490,7492],{"class":296,"line":328},[294,7489,2103],{"class":1376},[294,7491,2092],{"class":1195},[294,7493,1282],{"class":311},[294,7495,7496,7498,7500,7502,7504,7506],{"class":296,"line":340},[294,7497,2112],{"class":1376},[294,7499,2092],{"class":1195},[294,7501,2117],{"class":315},[294,7503,2120],{"class":1195},[294,7505,2123],{"class":315},[294,7507,1208],{"class":311},[294,7509,7510,7512,7514,7516],{"class":296,"line":351},[294,7511,2130],{"class":1376},[294,7513,2092],{"class":1195},[294,7515,2135],{"class":315},[294,7517,1208],{"class":311},[294,7519,7520,7522,7524,7526],{"class":296,"line":362},[294,7521,2142],{"class":1376},[294,7523,2092],{"class":1195},[294,7525,2147],{"class":315},[294,7527,1208],{"class":311},[294,7529,7530],{"class":296,"line":369},[294,7531,2154],{"class":311},[294,7533,7534],{"class":296,"line":377},[294,7535,2159],{"class":311},[294,7537,7538],{"class":296,"line":385},[294,7539,366],{"emptyLinePlaceholder":365},[294,7541,7542],{"class":296,"line":393},[294,7543,2168],{"class":300},[19,7545,2171],{},[79,7547,2175],{"id":2174},[19,7549,2178,7550,2183],{},[2180,7551,2182],{},[79,7553,2187],{"id":2186},[19,7555,2190,7556,2194],{},[291,7557,2193],{},[284,7559,7560],{"className":2197,"code":2198,"language":1875,"meta":289,"style":289},[291,7561,7562,7566,7572,7582,7592,7598,7608,7614,7620,7626,7630,7634,7638,7642],{"__ignoreMap":289},[294,7563,7564],{"class":296,"line":297},[294,7565,2205],{"class":311},[294,7567,7568,7570],{"class":296,"line":304},[294,7569,2210],{"class":315},[294,7571,2213],{"class":311},[294,7573,7574,7576,7578,7580],{"class":296,"line":319},[294,7575,2218],{"class":315},[294,7577,312],{"class":311},[294,7579,2223],{"class":336},[294,7581,1243],{"class":311},[294,7583,7584,7586,7588,7590],{"class":296,"line":328},[294,7585,2230],{"class":315},[294,7587,312],{"class":311},[294,7589,2235],{"class":336},[294,7591,1243],{"class":311},[294,7593,7594,7596],{"class":296,"line":340},[294,7595,2242],{"class":315},[294,7597,2213],{"class":311},[294,7599,7600,7602,7604,7606],{"class":296,"line":351},[294,7601,2249],{"class":315},[294,7603,312],{"class":311},[294,7605,2254],{"class":336},[294,7607,1243],{"class":311},[294,7609,7610,7612],{"class":296,"line":362},[294,7611,2261],{"class":315},[294,7613,2264],{"class":311},[294,7615,7616,7618],{"class":296,"line":369},[294,7617,2269],{"class":336},[294,7619,1243],{"class":311},[294,7621,7622,7624],{"class":296,"line":377},[294,7623,2276],{"class":336},[294,7625,1243],{"class":311},[294,7627,7628],{"class":296,"line":385},[294,7629,2283],{"class":336},[294,7631,7632],{"class":296,"line":393},[294,7633,2288],{"class":311},[294,7635,7636],{"class":296,"line":404},[294,7637,2293],{"class":311},[294,7639,7640],{"class":296,"line":415},[294,7641,2298],{"class":311},[294,7643,7644],{"class":296,"line":423},[294,7645,2159],{"class":311},[19,7647,2305],{},[14,7649,2309],{"id":2308},[19,7651,2312],{},[47,7653,7654,7658,7662,7666,7670],{},[50,7655,7656,2320],{},[23,7657,2319],{},[50,7659,7660,2326],{},[23,7661,2325],{},[50,7663,7664,2332],{},[23,7665,2331],{},[50,7667,7668,2338],{},[23,7669,2337],{},[50,7671,7672,2344],{},[23,7673,2343],{},[19,7675,2347],{},[19,7677,2350,7678,2355],{},[230,7679,2354],{"href":2353},[2357,7681],{},[19,7683,7684],{},[2180,7685,2363,7686,2368],{},[230,7687,2367],{"href":2366},[2370,7689,2372],{},{"title":289,"searchDepth":304,"depth":304,"links":7691},[7692,7693,7694,7699,7705,7712,7715,7722],{"id":16,"depth":304,"text":17},{"id":38,"depth":304,"text":39},{"id":73,"depth":304,"text":74,"children":7695},[7696,7697,7698],{"id":81,"depth":319,"text":82},{"id":97,"depth":319,"text":98},{"id":111,"depth":319,"text":112},{"id":214,"depth":304,"text":215,"children":7700},[7701,7702,7703,7704],{"id":221,"depth":319,"text":222},{"id":237,"depth":319,"text":238},{"id":244,"depth":319,"text":245},{"id":264,"depth":319,"text":265},{"id":271,"depth":304,"text":272,"children":7706},[7707,7708,7709,7710,7711],{"id":278,"depth":319,"text":279},{"id":1091,"depth":319,"text":1092},{"id":1174,"depth":319,"text":1175},{"id":1672,"depth":319,"text":1673},{"id":1727,"depth":319,"text":1728},{"id":1957,"depth":304,"text":1958,"children":7713},[7714],{"id":1964,"depth":319,"text":1965},{"id":2020,"depth":304,"text":2021,"children":7716},[7717,7718,7719,7720,7721],{"id":2027,"depth":319,"text":2028},{"id":2034,"depth":319,"text":2035},{"id":2053,"depth":319,"text":2054},{"id":2174,"depth":319,"text":2175},{"id":2186,"depth":319,"text":2187},{"id":2308,"depth":304,"text":2309},{},{"title":6,"description":2409},[2418,141,2419,2420],{"id":2423,"title":2424,"author":7727,"body":7728,"category":3613,"coverImage":2407,"date":3614,"description":3615,"extension":2410,"featured":365,"meta":8646,"navigation":365,"path":3617,"readingTime":3618,"seo":8647,"stem":3620,"tags":8648,"__hash__":3625},{"name":2426,"role":2427},{"type":11,"value":7729,"toc":8620},[7730,7732,7736,7738,7742,7744,7746,7748,7750,7752,7754,7756,7758,7760,7762,7764,7766,7784,8052,8056,8058,8060,8062,8064,8066,8068,8070,8338,8340,8342,8344,8394,8396,8400,8402,8404,8406,8408,8410,8414,8416,8418,8420,8422,8440,8442,8444,8446,8460,8462,8464,8466,8468,8478,8480,8482,8484,8506,8508,8510,8512,8574,8578,8584,8586,8588,8608,8610,8612,8618],[14,7731,2433],{"id":2432},[19,7733,2436,7734,2439],{},[23,7735,252],{},[19,7737,2442],{},[31,7739,7740],{},[19,7741,2447],{},[14,7743,2451],{"id":2450},[19,7745,2454],{},[79,7747,2458],{"id":2457},[19,7749,2461],{},[79,7751,2465],{"id":2464},[19,7753,2468],{},[79,7755,2472],{"id":2471},[19,7757,2475],{},[19,7759,2478],{},[79,7761,2482],{"id":2481},[19,7763,2485],{},[19,7765,2488],{},[47,7767,7768,7772,7776,7780],{},[50,7769,7770,2496],{},[23,7771,2495],{},[50,7773,7774,2502],{},[23,7775,2501],{},[50,7777,7778,2508],{},[23,7779,2507],{},[50,7781,7782,2514],{},[23,7783,2513],{},[284,7785,7786],{"className":1181,"code":2517,"language":1183,"meta":289,"style":289},[291,7787,7788,7792,7800,7810,7820,7830,7848,7852,7856,7866,7876,7886,7900,7914,7928,7932,7948,7960,7964,7968,7976,7980,7984,7990,8012,8028,8032,8036,8040,8044,8048],{"__ignoreMap":289},[294,7789,7790],{"class":296,"line":297},[294,7791,2524],{"class":300},[294,7793,7794,7796,7798],{"class":296,"line":304},[294,7795,2072],{"class":1195},[294,7797,2531],{"class":1112},[294,7799,1282],{"class":311},[294,7801,7802,7804,7806,7808],{"class":296,"line":319},[294,7803,2538],{"class":1376},[294,7805,2092],{"class":1195},[294,7807,2117],{"class":315},[294,7809,1208],{"class":311},[294,7811,7812,7814,7816,7818],{"class":296,"line":328},[294,7813,2549],{"class":1376},[294,7815,2092],{"class":1195},[294,7817,2117],{"class":315},[294,7819,1208],{"class":311},[294,7821,7822,7824,7826,7828],{"class":296,"line":340},[294,7823,2560],{"class":1376},[294,7825,2092],{"class":1195},[294,7827,2147],{"class":315},[294,7829,1208],{"class":311},[294,7831,7832,7834,7836,7838,7840,7842,7844,7846],{"class":296,"line":351},[294,7833,2571],{"class":1376},[294,7835,2092],{"class":1195},[294,7837,2576],{"class":1112},[294,7839,2078],{"class":311},[294,7841,2581],{"class":315},[294,7843,1295],{"class":311},[294,7845,2586],{"class":315},[294,7847,2589],{"class":311},[294,7849,7850],{"class":296,"line":362},[294,7851,2159],{"class":311},[294,7853,7854],{"class":296,"line":369},[294,7855,366],{"emptyLinePlaceholder":365},[294,7857,7858,7860,7862,7864],{"class":296,"line":377},[294,7859,1298],{"class":1195},[294,7861,2604],{"class":1195},[294,7863,2607],{"class":1112},[294,7865,2610],{"class":311},[294,7867,7868,7870,7872,7874],{"class":296,"line":385},[294,7869,2615],{"class":1376},[294,7871,2092],{"class":1195},[294,7873,2117],{"class":315},[294,7875,1243],{"class":311},[294,7877,7878,7880,7882,7884],{"class":296,"line":393},[294,7879,2626],{"class":1376},[294,7881,2092],{"class":1195},[294,7883,2117],{"class":315},[294,7885,1243],{"class":311},[294,7887,7888,7890,7892,7894,7896,7898],{"class":296,"line":404},[294,7889,2637],{"class":1376},[294,7891,2092],{"class":1195},[294,7893,2147],{"class":315},[294,7895,1223],{"class":1195},[294,7897,2646],{"class":315},[294,7899,1243],{"class":311},[294,7901,7902,7904,7906,7908,7910,7912],{"class":296,"line":415},[294,7903,2653],{"class":311},[294,7905,2092],{"class":1195},[294,7907,2658],{"class":1112},[294,7909,2078],{"class":311},[294,7911,2663],{"class":1112},[294,7913,2666],{"class":311},[294,7915,7916,7918,7920,7922,7924,7926],{"class":296,"line":423},[294,7917,2671],{"class":1195},[294,7919,2674],{"class":315},[294,7921,1223],{"class":1195},[294,7923,1590],{"class":1195},[294,7925,2681],{"class":1112},[294,7927,2684],{"class":311},[294,7929,7930],{"class":296,"line":432},[294,7931,366],{"emptyLinePlaceholder":365},[294,7933,7934,7936,7938,7940,7942,7944,7946],{"class":296,"line":440},[294,7935,2671],{"class":1195},[294,7937,2695],{"class":315},[294,7939,1223],{"class":1195},[294,7941,1590],{"class":1195},[294,7943,2702],{"class":311},[294,7945,2705],{"class":1112},[294,7947,1232],{"class":311},[294,7949,7950,7952,7954,7956,7958],{"class":296,"line":451},[294,7951,2712],{"class":311},[294,7953,2715],{"class":336},[294,7955,2718],{"class":311},[294,7957,2721],{"class":336},[294,7959,1243],{"class":311},[294,7961,7962],{"class":296,"line":459},[294,7963,2728],{"class":311},[294,7965,7966],{"class":296,"line":467},[294,7967,2733],{"class":311},[294,7969,7970,7972,7974],{"class":296,"line":475},[294,7971,2738],{"class":311},[294,7973,2741],{"class":315},[294,7975,2744],{"class":311},[294,7977,7978],{"class":296,"line":486},[294,7979,1662],{"class":311},[294,7981,7982],{"class":296,"line":494},[294,7983,366],{"emptyLinePlaceholder":365},[294,7985,7986,7988],{"class":296,"line":502},[294,7987,2757],{"class":1195},[294,7989,2760],{"class":311},[294,7991,7992,7994,7996,7998,8000,8002,8004,8006,8008,8010],{"class":296,"line":513},[294,7993,2765],{"class":311},[294,7995,2768],{"class":1112},[294,7997,2771],{"class":311},[294,7999,2774],{"class":1376},[294,8001,1380],{"class":311},[294,8003,1279],{"class":1195},[294,8005,2781],{"class":311},[294,8007,2784],{"class":1195},[294,8009,2787],{"class":315},[294,8011,1339],{"class":311},[294,8013,8014,8016,8018,8020,8022,8024,8026],{"class":296,"line":521},[294,8015,2765],{"class":311},[294,8017,2796],{"class":1112},[294,8019,2771],{"class":311},[294,8021,2774],{"class":1376},[294,8023,1380],{"class":311},[294,8025,1279],{"class":1195},[294,8027,2807],{"class":311},[294,8029,8030],{"class":296,"line":529},[294,8031,2812],{"class":311},[294,8033,8034],{"class":296,"line":537},[294,8035,2817],{"class":311},[294,8037,8038],{"class":296,"line":548},[294,8039,2822],{"class":311},[294,8041,8042],{"class":296,"line":556},[294,8043,2827],{"class":311},[294,8045,8046],{"class":296,"line":566},[294,8047,2832],{"class":311},[294,8049,8050],{"class":296,"line":573},[294,8051,2159],{"class":311},[1162,8053,8054],{"type":322},[19,8055,2841],{},[79,8057,2845],{"id":2844},[19,8059,2848],{},[19,8061,2851],{},[14,8063,2855],{"id":2854},[19,8065,2858],{},[79,8067,2862],{"id":2861},[19,8069,2865],{},[284,8071,8072],{"className":1181,"code":2868,"language":1183,"meta":289,"style":289},[291,8073,8074,8078,8088,8096,8100,8106,8110,8118,8122,8126,8134,8142,8162,8166,8170,8178,8186,8194,8198,8202,8210,8226,8234,8238,8242,8250,8258,8262,8266,8274,8282,8286,8290,8298,8306,8310,8314,8330,8334],{"__ignoreMap":289},[294,8075,8076],{"class":296,"line":297},[294,8077,2875],{"class":300},[294,8079,8080,8082,8084,8086],{"class":296,"line":304},[294,8081,1217],{"class":1195},[294,8083,2882],{"class":315},[294,8085,1223],{"class":1195},[294,8087,1282],{"class":311},[294,8089,8090,8092,8094],{"class":296,"line":319},[294,8091,2891],{"class":311},[294,8093,2894],{"class":336},[294,8095,1243],{"class":311},[294,8097,8098],{"class":296,"line":328},[294,8099,2901],{"class":311},[294,8101,8102,8104],{"class":296,"line":340},[294,8103,2906],{"class":336},[294,8105,1243],{"class":311},[294,8107,8108],{"class":296,"line":351},[294,8109,2913],{"class":311},[294,8111,8112,8114,8116],{"class":296,"line":362},[294,8113,2918],{"class":311},[294,8115,2921],{"class":336},[294,8117,1243],{"class":311},[294,8119,8120],{"class":296,"line":369},[294,8121,2928],{"class":311},[294,8123,8124],{"class":296,"line":377},[294,8125,2933],{"class":311},[294,8127,8128,8130,8132],{"class":296,"line":385},[294,8129,2938],{"class":311},[294,8131,2941],{"class":336},[294,8133,1243],{"class":311},[294,8135,8136,8138,8140],{"class":296,"line":393},[294,8137,2948],{"class":311},[294,8139,2951],{"class":336},[294,8141,1243],{"class":311},[294,8143,8144,8146,8148,8150,8152,8154,8156,8158,8160],{"class":296,"line":404},[294,8145,2958],{"class":311},[294,8147,1428],{"class":336},[294,8149,1295],{"class":311},[294,8151,2965],{"class":336},[294,8153,1295],{"class":311},[294,8155,2970],{"class":336},[294,8157,1295],{"class":311},[294,8159,2975],{"class":336},[294,8161,2978],{"class":311},[294,8163,8164],{"class":296,"line":415},[294,8165,2983],{"class":311},[294,8167,8168],{"class":296,"line":423},[294,8169,2988],{"class":311},[294,8171,8172,8174,8176],{"class":296,"line":432},[294,8173,2938],{"class":311},[294,8175,2941],{"class":336},[294,8177,1243],{"class":311},[294,8179,8180,8182,8184],{"class":296,"line":440},[294,8181,3001],{"class":311},[294,8183,3004],{"class":336},[294,8185,1243],{"class":311},[294,8187,8188,8190,8192],{"class":296,"line":451},[294,8189,2948],{"class":311},[294,8191,3013],{"class":336},[294,8193,1243],{"class":311},[294,8195,8196],{"class":296,"line":459},[294,8197,2983],{"class":311},[294,8199,8200],{"class":296,"line":467},[294,8201,3024],{"class":311},[294,8203,8204,8206,8208],{"class":296,"line":475},[294,8205,2938],{"class":311},[294,8207,2941],{"class":336},[294,8209,1243],{"class":311},[294,8211,8212,8214,8216,8218,8220,8222,8224],{"class":296,"line":486},[294,8213,2958],{"class":311},[294,8215,3039],{"class":336},[294,8217,1295],{"class":311},[294,8219,3044],{"class":336},[294,8221,1295],{"class":311},[294,8223,3049],{"class":336},[294,8225,2978],{"class":311},[294,8227,8228,8230,8232],{"class":296,"line":494},[294,8229,2948],{"class":311},[294,8231,3058],{"class":336},[294,8233,1243],{"class":311},[294,8235,8236],{"class":296,"line":502},[294,8237,2983],{"class":311},[294,8239,8240],{"class":296,"line":513},[294,8241,3069],{"class":311},[294,8243,8244,8246,8248],{"class":296,"line":521},[294,8245,2938],{"class":311},[294,8247,2941],{"class":336},[294,8249,1243],{"class":311},[294,8251,8252,8254,8256],{"class":296,"line":529},[294,8253,2948],{"class":311},[294,8255,3084],{"class":336},[294,8257,1243],{"class":311},[294,8259,8260],{"class":296,"line":537},[294,8261,2983],{"class":311},[294,8263,8264],{"class":296,"line":548},[294,8265,3095],{"class":311},[294,8267,8268,8270,8272],{"class":296,"line":556},[294,8269,2938],{"class":311},[294,8271,2941],{"class":336},[294,8273,1243],{"class":311},[294,8275,8276,8278,8280],{"class":296,"line":566},[294,8277,2948],{"class":311},[294,8279,3110],{"class":336},[294,8281,1243],{"class":311},[294,8283,8284],{"class":296,"line":573},[294,8285,2983],{"class":311},[294,8287,8288],{"class":296,"line":580},[294,8289,3121],{"class":311},[294,8291,8292,8294,8296],{"class":296,"line":587},[294,8293,2938],{"class":311},[294,8295,2941],{"class":336},[294,8297,1243],{"class":311},[294,8299,8300,8302,8304],{"class":296,"line":597},[294,8301,2948],{"class":311},[294,8303,3136],{"class":336},[294,8305,1243],{"class":311},[294,8307,8308],{"class":296,"line":605},[294,8309,2983],{"class":311},[294,8311,8312],{"class":296,"line":615},[294,8313,3147],{"class":311},[294,8315,8316,8318,8320,8322,8324,8326,8328],{"class":296,"line":622},[294,8317,3152],{"class":311},[294,8319,3155],{"class":336},[294,8321,1295],{"class":311},[294,8323,3160],{"class":336},[294,8325,1295],{"class":311},[294,8327,3165],{"class":336},[294,8329,2978],{"class":311},[294,8331,8332],{"class":296,"line":629},[294,8333,1922],{"class":311},[294,8335,8336],{"class":296,"line":636},[294,8337,3176],{"class":311},[79,8339,3180],{"id":3179},[19,8341,3183],{},[19,8343,3186],{},[47,8345,8346,8350,8356,8360,8364,8368,8372,8376,8380,8384,8390],{},[50,8347,8348,3194],{},[23,8349,3193],{},[50,8351,8352,3200,8354],{},[23,8353,3199],{},[291,8355,3203],{},[50,8357,8358,3209],{},[23,8359,3208],{},[50,8361,8362,3214],{},[23,8363,3199],{},[50,8365,8366,3219],{},[23,8367,3193],{},[50,8369,8370,3224],{},[23,8371,3199],{},[50,8373,8374,3229],{},[23,8375,3193],{},[50,8377,8378,3234],{},[23,8379,3199],{},[50,8381,8382,3239],{},[23,8383,3193],{},[50,8385,8386,3200,8388],{},[23,8387,3199],{},[291,8389,3246],{},[50,8391,8392,3251],{},[23,8393,3199],{},[19,8395,3254],{},[1162,8397,8398],{"type":1164},[19,8399,3259],{},[14,8401,3263],{"id":3262},[19,8403,3266],{},[79,8405,3270],{"id":3269},[19,8407,3273],{},[79,8409,3277],{"id":3276},[19,8411,3280,8412,3284],{},[230,8413,3283],{"href":2353},[14,8415,3288],{"id":3287},[19,8417,3291],{},[79,8419,3295],{"id":3294},[19,8421,3298],{},[1711,8423,8424,8428,8432,8436],{},[50,8425,8426,3306],{},[23,8427,3305],{},[50,8429,8430,3312],{},[23,8431,3311],{},[50,8433,8434,3318],{},[23,8435,3317],{},[50,8437,8438,3324],{},[23,8439,3323],{},[79,8441,3328],{"id":3327},[19,8443,3331],{},[19,8445,3334],{},[47,8447,8448,8452,8456],{},[50,8449,8450,3342],{},[23,8451,3341],{},[50,8453,8454,3348],{},[23,8455,3347],{},[50,8457,8458,3354],{},[23,8459,3353],{},[19,8461,3357],{},[79,8463,3361],{"id":3360},[19,8465,3364],{},[19,8467,3367],{},[1711,8469,8470,8472,8474,8476],{},[50,8471,3372],{},[50,8473,3375],{},[50,8475,3378],{},[50,8477,3381],{},[19,8479,3384],{},[79,8481,3388],{"id":3387},[19,8483,3391],{},[1711,8485,8486,8490,8494,8498,8502],{},[50,8487,8488,3399],{},[23,8489,3398],{},[50,8491,8492,3405],{},[23,8493,3404],{},[50,8495,8496,3411],{},[23,8497,3410],{},[50,8499,8500,3417],{},[23,8501,3416],{},[50,8503,8504,3423],{},[23,8505,3422],{},[19,8507,3426],{},[14,8509,3430],{"id":3429},[19,8511,3433],{},[124,8513,8514,8524],{},[127,8515,8516],{},[130,8517,8518,8520,8522],{},[133,8519,3442],{},[133,8521,3445],{},[133,8523,3448],{},[143,8525,8526,8534,8542,8550,8558,8566],{},[130,8527,8528,8530,8532],{},[148,8529,3455],{},[148,8531,3458],{},[148,8533,3461],{},[130,8535,8536,8538,8540],{},[148,8537,3466],{},[148,8539,3469],{},[148,8541,3472],{},[130,8543,8544,8546,8548],{},[148,8545,3477],{},[148,8547,3480],{},[148,8549,3483],{},[130,8551,8552,8554,8556],{},[148,8553,3488],{},[148,8555,3491],{},[148,8557,3494],{},[130,8559,8560,8562,8564],{},[148,8561,3499],{},[148,8563,3502],{},[148,8565,3505],{},[130,8567,8568,8570,8572],{},[148,8569,3510],{},[148,8571,3513],{},[148,8573,3516],{},[19,8575,3519,8576,3523],{},[230,8577,3522],{"href":251},[1162,8579,8580],{"type":322},[19,8581,3528,8582,3532],{},[2180,8583,3531],{},[14,8585,3536],{"id":3535},[19,8587,3539],{},[1711,8589,8590,8594,8598,8604],{},[50,8591,8592,3547],{},[23,8593,3546],{},[50,8595,8596,3553],{},[23,8597,3552],{},[50,8599,8600,3563],{},[23,8601,3558,8602],{},[230,8603,3562],{"href":3561},[50,8605,8606,3569],{},[23,8607,3568],{},[19,8609,3572],{},[2357,8611],{},[19,8613,8614],{},[2180,8615,3579,8616,3583],{},[230,8617,3582],{"href":2366},[2370,8619,3586],{},{"title":289,"searchDepth":304,"depth":304,"links":8621},[8622,8623,8630,8634,8638,8644,8645],{"id":2432,"depth":304,"text":2433},{"id":2450,"depth":304,"text":2451,"children":8624},[8625,8626,8627,8628,8629],{"id":2457,"depth":319,"text":2458},{"id":2464,"depth":319,"text":2465},{"id":2471,"depth":319,"text":2472},{"id":2481,"depth":319,"text":2482},{"id":2844,"depth":319,"text":2845},{"id":2854,"depth":304,"text":2855,"children":8631},[8632,8633],{"id":2861,"depth":319,"text":2862},{"id":3179,"depth":319,"text":3180},{"id":3262,"depth":304,"text":3263,"children":8635},[8636,8637],{"id":3269,"depth":319,"text":3270},{"id":3276,"depth":319,"text":3277},{"id":3287,"depth":304,"text":3288,"children":8639},[8640,8641,8642,8643],{"id":3294,"depth":319,"text":3295},{"id":3327,"depth":319,"text":3328},{"id":3360,"depth":319,"text":3361},{"id":3387,"depth":319,"text":3388},{"id":3429,"depth":304,"text":3430},{"id":3535,"depth":304,"text":3536},{},{"title":2424,"description":3615},[252,3622,3623,3624],{"id":8650,"title":8651,"author":8652,"body":8655,"category":5922,"coverImage":2407,"date":9823,"description":9824,"extension":2410,"featured":2411,"meta":9825,"navigation":365,"path":9826,"readingTime":9827,"seo":9828,"stem":9829,"tags":9830,"__hash__":9833},"blog/blog/cloud-native-architecture.md","Cloud-Native Architecture: Building for Global Scale",{"name":8653,"role":8654},"Kavinda Silva","Principal Architect",{"type":11,"value":8656,"toc":9812},[8657,8661,8664,8668,8672,8675,9059,9369,9373,9376,9379,9399,9404,9408,9411,9431,9436,9440,9443,9687,9693,9697,9700,9703,9729,9733,9736,9796,9799,9801,9809],[14,8658,8660],{"id":8659},"beyond-containers-true-cloud-native-thinking","Beyond Containers: True Cloud-Native Thinking",[19,8662,8663],{},"Cloud-native isn't just about running containers in Kubernetes. It's a philosophy — a way of designing systems that fully exploits the cloud's elastic, distributed nature. After architecting platforms that serve millions of users across four continents, we've distilled our approach into core principles.",[14,8665,8667],{"id":8666},"the-three-pillars-of-cloud-native-architecture","The Three Pillars of Cloud-Native Architecture",[79,8669,8671],{"id":8670},"_1-resilience-as-a-first-class-concern","1. Resilience as a First-Class Concern",[19,8673,8674],{},"Every service must be designed to fail gracefully. This isn't pessimism — it's engineering reality. In a distributed system with hundreds of services, something is always failing.",[284,8676,8680],{"className":8677,"code":8678,"language":8679,"meta":289,"style":289},"language-go shiki shiki-themes github-light github-dark","// Circuit breaker pattern in Go\ntype CircuitBreaker struct {\n    maxFailures   int\n    resetTimeout  time.Duration\n    failures      int\n    lastFailure   time.Time\n    state         State\n    mu            sync.Mutex\n}\n\nfunc (cb *CircuitBreaker) Execute(fn func() error) error {\n    cb.mu.Lock()\n    if cb.state == Open {\n        if time.Since(cb.lastFailure) > cb.resetTimeout {\n            cb.state = HalfOpen\n        } else {\n            cb.mu.Unlock()\n            return ErrCircuitOpen\n        }\n    }\n    cb.mu.Unlock()\n\n    err := fn()\n    cb.mu.Lock()\n    defer cb.mu.Unlock()\n\n    if err != nil {\n        cb.failures++\n        cb.lastFailure = time.Now()\n        if cb.failures >= cb.maxFailures {\n            cb.state = Open\n        }\n        return err\n    }\n\n    cb.failures = 0\n    cb.state = Closed\n    return nil\n}\n","go",[291,8681,8682,8687,8699,8707,8720,8727,8739,8747,8760,8764,8768,8808,8818,8832,8851,8862,8872,8882,8890,8895,8899,8907,8911,8924,8932,8944,8948,8963,8971,8985,8998,9007,9011,9019,9023,9027,9037,9047,9055],{"__ignoreMap":289},[294,8683,8684],{"class":296,"line":297},[294,8685,8686],{"class":300},"// Circuit breaker pattern in Go\n",[294,8688,8689,8691,8694,8697],{"class":296,"line":304},[294,8690,5387],{"class":1195},[294,8692,8693],{"class":1112}," CircuitBreaker",[294,8695,8696],{"class":1195}," struct",[294,8698,1282],{"class":311},[294,8700,8701,8704],{"class":296,"line":319},[294,8702,8703],{"class":311},"    maxFailures   ",[294,8705,8706],{"class":1195},"int\n",[294,8708,8709,8712,8715,8717],{"class":296,"line":328},[294,8710,8711],{"class":311},"    resetTimeout  ",[294,8713,8714],{"class":1112},"time",[294,8716,4250],{"class":311},[294,8718,8719],{"class":1112},"Duration\n",[294,8721,8722,8725],{"class":296,"line":340},[294,8723,8724],{"class":311},"    failures      ",[294,8726,8706],{"class":1195},[294,8728,8729,8732,8734,8736],{"class":296,"line":351},[294,8730,8731],{"class":311},"    lastFailure   ",[294,8733,8714],{"class":1112},[294,8735,4250],{"class":311},[294,8737,8738],{"class":1112},"Time\n",[294,8740,8741,8744],{"class":296,"line":362},[294,8742,8743],{"class":311},"    state         ",[294,8745,8746],{"class":1112},"State\n",[294,8748,8749,8752,8755,8757],{"class":296,"line":369},[294,8750,8751],{"class":311},"    mu            ",[294,8753,8754],{"class":1112},"sync",[294,8756,4250],{"class":311},[294,8758,8759],{"class":1112},"Mutex\n",[294,8761,8762],{"class":296,"line":377},[294,8763,2159],{"class":311},[294,8765,8766],{"class":296,"line":385},[294,8767,366],{"emptyLinePlaceholder":365},[294,8769,8770,8773,8775,8778,8781,8784,8786,8789,8791,8794,8797,8800,8802,8804,8806],{"class":296,"line":393},[294,8771,8772],{"class":1195},"func",[294,8774,1568],{"class":311},[294,8776,8777],{"class":1376},"cb ",[294,8779,8780],{"class":1195},"*",[294,8782,8783],{"class":1112},"CircuitBreaker",[294,8785,1380],{"class":311},[294,8787,8788],{"class":1112},"Execute",[294,8790,1270],{"class":311},[294,8792,8793],{"class":1376},"fn",[294,8795,8796],{"class":1195}," func",[294,8798,8799],{"class":311},"() ",[294,8801,5484],{"class":1195},[294,8803,1380],{"class":311},[294,8805,5484],{"class":1195},[294,8807,1282],{"class":311},[294,8809,8810,8813,8816],{"class":296,"line":404},[294,8811,8812],{"class":311},"    cb.mu.",[294,8814,8815],{"class":1112},"Lock",[294,8817,1324],{"class":311},[294,8819,8820,8823,8826,8829],{"class":296,"line":415},[294,8821,8822],{"class":1195},"    if",[294,8824,8825],{"class":311}," cb.state ",[294,8827,8828],{"class":1195},"==",[294,8830,8831],{"class":311}," Open {\n",[294,8833,8834,8837,8840,8843,8846,8848],{"class":296,"line":423},[294,8835,8836],{"class":1195},"        if",[294,8838,8839],{"class":311}," time.",[294,8841,8842],{"class":1112},"Since",[294,8844,8845],{"class":311},"(cb.lastFailure) ",[294,8847,2784],{"class":1195},[294,8849,8850],{"class":311}," cb.resetTimeout {\n",[294,8852,8853,8856,8859],{"class":296,"line":432},[294,8854,8855],{"class":311},"            cb.state ",[294,8857,8858],{"class":1195},"=",[294,8860,8861],{"class":311}," HalfOpen\n",[294,8863,8864,8867,8870],{"class":296,"line":440},[294,8865,8866],{"class":311},"        } ",[294,8868,8869],{"class":1195},"else",[294,8871,1282],{"class":311},[294,8873,8874,8877,8880],{"class":296,"line":451},[294,8875,8876],{"class":311},"            cb.mu.",[294,8878,8879],{"class":1112},"Unlock",[294,8881,1324],{"class":311},[294,8883,8884,8887],{"class":296,"line":459},[294,8885,8886],{"class":1195},"            return",[294,8888,8889],{"class":311}," ErrCircuitOpen\n",[294,8891,8892],{"class":296,"line":467},[294,8893,8894],{"class":311},"        }\n",[294,8896,8897],{"class":296,"line":475},[294,8898,2293],{"class":311},[294,8900,8901,8903,8905],{"class":296,"line":486},[294,8902,8812],{"class":311},[294,8904,8879],{"class":1112},[294,8906,1324],{"class":311},[294,8908,8909],{"class":296,"line":494},[294,8910,366],{"emptyLinePlaceholder":365},[294,8912,8913,8916,8919,8922],{"class":296,"line":502},[294,8914,8915],{"class":311},"    err ",[294,8917,8918],{"class":1195},":=",[294,8920,8921],{"class":1112}," fn",[294,8923,1324],{"class":311},[294,8925,8926,8928,8930],{"class":296,"line":513},[294,8927,8812],{"class":311},[294,8929,8815],{"class":1112},[294,8931,1324],{"class":311},[294,8933,8934,8937,8940,8942],{"class":296,"line":521},[294,8935,8936],{"class":1195},"    defer",[294,8938,8939],{"class":311}," cb.mu.",[294,8941,8879],{"class":1112},[294,8943,1324],{"class":311},[294,8945,8946],{"class":296,"line":529},[294,8947,366],{"emptyLinePlaceholder":365},[294,8949,8950,8952,8955,8958,8961],{"class":296,"line":537},[294,8951,8822],{"class":1195},[294,8953,8954],{"class":311}," err ",[294,8956,8957],{"class":1195},"!=",[294,8959,8960],{"class":315}," nil",[294,8962,1282],{"class":311},[294,8964,8965,8968],{"class":296,"line":548},[294,8966,8967],{"class":311},"        cb.failures",[294,8969,8970],{"class":1195},"++\n",[294,8972,8973,8976,8978,8980,8983],{"class":296,"line":556},[294,8974,8975],{"class":311},"        cb.lastFailure ",[294,8977,8858],{"class":1195},[294,8979,8839],{"class":311},[294,8981,8982],{"class":1112},"Now",[294,8984,1324],{"class":311},[294,8986,8987,8989,8992,8995],{"class":296,"line":566},[294,8988,8836],{"class":1195},[294,8990,8991],{"class":311}," cb.failures ",[294,8993,8994],{"class":1195},">=",[294,8996,8997],{"class":311}," cb.maxFailures {\n",[294,8999,9000,9002,9004],{"class":296,"line":573},[294,9001,8855],{"class":311},[294,9003,8858],{"class":1195},[294,9005,9006],{"class":311}," Open\n",[294,9008,9009],{"class":296,"line":580},[294,9010,8894],{"class":311},[294,9012,9013,9016],{"class":296,"line":587},[294,9014,9015],{"class":1195},"        return",[294,9017,9018],{"class":311}," err\n",[294,9020,9021],{"class":296,"line":597},[294,9022,2293],{"class":311},[294,9024,9025],{"class":296,"line":605},[294,9026,366],{"emptyLinePlaceholder":365},[294,9028,9029,9032,9034],{"class":296,"line":615},[294,9030,9031],{"class":311},"    cb.failures ",[294,9033,8858],{"class":1195},[294,9035,9036],{"class":315}," 0\n",[294,9038,9039,9042,9044],{"class":296,"line":622},[294,9040,9041],{"class":311},"    cb.state ",[294,9043,8858],{"class":1195},[294,9045,9046],{"class":311}," Closed\n",[294,9048,9049,9052],{"class":296,"line":629},[294,9050,9051],{"class":1195},"    return",[294,9053,9054],{"class":315}," nil\n",[294,9056,9057],{"class":296,"line":636},[294,9058,2159],{"class":311},[284,9060,9062],{"className":286,"code":9061,"language":288,"meta":289,"style":289},"# Kubernetes deployment with resilience patterns\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: payment-service\nspec:\n  replicas: 3\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxUnavailable: 1\n      maxSurge: 1\n  template:\n    spec:\n      containers:\n        - name: payment\n          image: cnex/payment:v2.4.1\n          resources:\n            requests:\n              memory: \"256Mi\"\n              cpu: \"250m\"\n            limits:\n              memory: \"512Mi\"\n              cpu: \"500m\"\n          livenessProbe:\n            httpGet:\n              path: /healthz\n              port: 8080\n            initialDelaySeconds: 15\n            periodSeconds: 10\n          readinessProbe:\n            httpGet:\n              path: /readyz\n              port: 8080\n            initialDelaySeconds: 5\n            periodSeconds: 5\n",[291,9063,9064,9069,9079,9089,9096,9106,9113,9123,9130,9140,9147,9157,9166,9173,9180,9187,9199,9209,9216,9223,9233,9243,9250,9259,9268,9275,9282,9292,9302,9312,9322,9329,9335,9344,9352,9361],{"__ignoreMap":289},[294,9065,9066],{"class":296,"line":297},[294,9067,9068],{"class":300},"# Kubernetes deployment with resilience patterns\n",[294,9070,9071,9074,9076],{"class":296,"line":304},[294,9072,9073],{"class":307},"apiVersion",[294,9075,312],{"class":311},[294,9077,9078],{"class":336},"apps/v1\n",[294,9080,9081,9084,9086],{"class":296,"line":319},[294,9082,9083],{"class":307},"kind",[294,9085,312],{"class":311},[294,9087,9088],{"class":336},"Deployment\n",[294,9090,9091,9094],{"class":296,"line":328},[294,9092,9093],{"class":307},"metadata",[294,9095,325],{"class":311},[294,9097,9098,9101,9103],{"class":296,"line":340},[294,9099,9100],{"class":307},"  name",[294,9102,312],{"class":311},[294,9104,9105],{"class":336},"payment-service\n",[294,9107,9108,9111],{"class":296,"line":351},[294,9109,9110],{"class":307},"spec",[294,9112,325],{"class":311},[294,9114,9115,9118,9120],{"class":296,"line":362},[294,9116,9117],{"class":307},"  replicas",[294,9119,312],{"class":311},[294,9121,9122],{"class":315},"3\n",[294,9124,9125,9128],{"class":296,"line":369},[294,9126,9127],{"class":307},"  strategy",[294,9129,325],{"class":311},[294,9131,9132,9135,9137],{"class":296,"line":377},[294,9133,9134],{"class":307},"    type",[294,9136,312],{"class":311},[294,9138,9139],{"class":336},"RollingUpdate\n",[294,9141,9142,9145],{"class":296,"line":385},[294,9143,9144],{"class":307},"    rollingUpdate",[294,9146,325],{"class":311},[294,9148,9149,9152,9154],{"class":296,"line":393},[294,9150,9151],{"class":307},"      maxUnavailable",[294,9153,312],{"class":311},[294,9155,9156],{"class":315},"1\n",[294,9158,9159,9162,9164],{"class":296,"line":404},[294,9160,9161],{"class":307},"      maxSurge",[294,9163,312],{"class":311},[294,9165,9156],{"class":315},[294,9167,9168,9171],{"class":296,"line":415},[294,9169,9170],{"class":307},"  template",[294,9172,325],{"class":311},[294,9174,9175,9178],{"class":296,"line":423},[294,9176,9177],{"class":307},"    spec",[294,9179,325],{"class":311},[294,9181,9182,9185],{"class":296,"line":432},[294,9183,9184],{"class":307},"      containers",[294,9186,325],{"class":311},[294,9188,9189,9191,9194,9196],{"class":296,"line":440},[294,9190,426],{"class":311},[294,9192,9193],{"class":307},"name",[294,9195,312],{"class":311},[294,9197,9198],{"class":336},"payment\n",[294,9200,9201,9204,9206],{"class":296,"line":451},[294,9202,9203],{"class":307},"          image",[294,9205,312],{"class":311},[294,9207,9208],{"class":336},"cnex/payment:v2.4.1\n",[294,9210,9211,9214],{"class":296,"line":459},[294,9212,9213],{"class":307},"          resources",[294,9215,325],{"class":311},[294,9217,9218,9221],{"class":296,"line":467},[294,9219,9220],{"class":307},"            requests",[294,9222,325],{"class":311},[294,9224,9225,9228,9230],{"class":296,"line":475},[294,9226,9227],{"class":307},"              memory",[294,9229,312],{"class":311},[294,9231,9232],{"class":336},"\"256Mi\"\n",[294,9234,9235,9238,9240],{"class":296,"line":486},[294,9236,9237],{"class":307},"              cpu",[294,9239,312],{"class":311},[294,9241,9242],{"class":336},"\"250m\"\n",[294,9244,9245,9248],{"class":296,"line":494},[294,9246,9247],{"class":307},"            limits",[294,9249,325],{"class":311},[294,9251,9252,9254,9256],{"class":296,"line":502},[294,9253,9227],{"class":307},[294,9255,312],{"class":311},[294,9257,9258],{"class":336},"\"512Mi\"\n",[294,9260,9261,9263,9265],{"class":296,"line":513},[294,9262,9237],{"class":307},[294,9264,312],{"class":311},[294,9266,9267],{"class":336},"\"500m\"\n",[294,9269,9270,9273],{"class":296,"line":521},[294,9271,9272],{"class":307},"          livenessProbe",[294,9274,325],{"class":311},[294,9276,9277,9280],{"class":296,"line":529},[294,9278,9279],{"class":307},"            httpGet",[294,9281,325],{"class":311},[294,9283,9284,9287,9289],{"class":296,"line":537},[294,9285,9286],{"class":307},"              path",[294,9288,312],{"class":311},[294,9290,9291],{"class":336},"/healthz\n",[294,9293,9294,9297,9299],{"class":296,"line":548},[294,9295,9296],{"class":307},"              port",[294,9298,312],{"class":311},[294,9300,9301],{"class":315},"8080\n",[294,9303,9304,9307,9309],{"class":296,"line":556},[294,9305,9306],{"class":307},"            initialDelaySeconds",[294,9308,312],{"class":311},[294,9310,9311],{"class":315},"15\n",[294,9313,9314,9317,9319],{"class":296,"line":566},[294,9315,9316],{"class":307},"            periodSeconds",[294,9318,312],{"class":311},[294,9320,9321],{"class":315},"10\n",[294,9323,9324,9327],{"class":296,"line":573},[294,9325,9326],{"class":307},"          readinessProbe",[294,9328,325],{"class":311},[294,9330,9331,9333],{"class":296,"line":580},[294,9332,9279],{"class":307},[294,9334,325],{"class":311},[294,9336,9337,9339,9341],{"class":296,"line":587},[294,9338,9286],{"class":307},[294,9340,312],{"class":311},[294,9342,9343],{"class":336},"/readyz\n",[294,9345,9346,9348,9350],{"class":296,"line":597},[294,9347,9296],{"class":307},[294,9349,312],{"class":311},[294,9351,9301],{"class":315},[294,9353,9354,9356,9358],{"class":296,"line":605},[294,9355,9306],{"class":307},[294,9357,312],{"class":311},[294,9359,9360],{"class":315},"5\n",[294,9362,9363,9365,9367],{"class":296,"line":615},[294,9364,9316],{"class":307},[294,9366,312],{"class":311},[294,9368,9360],{"class":315},[79,9370,9372],{"id":9371},"_2-observability-over-monitoring","2. Observability Over Monitoring",[19,9374,9375],{},"Traditional monitoring asks \"Is it up?\" Observability asks \"Why is it behaving this way?\" The difference is critical at scale.",[19,9377,9378],{},"We instrument every service with three pillars of observability:",[1711,9380,9381,9387,9393],{},[50,9382,9383,9386],{},[23,9384,9385],{},"Structured logging"," with correlation IDs that trace requests across service boundaries",[50,9388,9389,9392],{},[23,9390,9391],{},"Distributed tracing"," via OpenTelemetry, giving us end-to-end request visibility",[50,9394,9395,9398],{},[23,9396,9397],{},"Metrics"," with dimensional tagging for flexible querying and alerting",[1162,9400,9401],{"type":322},[19,9402,9403],{},"A well-instrumented system should allow any engineer to diagnose a production issue within 5 minutes, without needing to be the service owner.",[79,9405,9407],{"id":9406},"_3-progressive-delivery","3. Progressive Delivery",[19,9409,9410],{},"Deploying to production should be boring. We achieve this through a layered deployment strategy:",[47,9412,9413,9419,9425],{},[50,9414,9415,9418],{},[23,9416,9417],{},"Canary releases"," — 5% of traffic to the new version, automated rollback on error spike",[50,9420,9421,9424],{},[23,9422,9423],{},"Feature flags"," — Decouple deployment from release, ship code dark",[50,9426,9427,9430],{},[23,9428,9429],{},"Blue-green environments"," — Zero-downtime database migrations and infrastructure changes",[31,9432,9433],{},[19,9434,9435],{},"We deploy to production an average of 47 times per day across our platform. Not because we're reckless — because our delivery pipeline makes it safe.",[14,9437,9439],{"id":9438},"infrastructure-as-code-the-complete-stack","Infrastructure as Code: The Complete Stack",[19,9441,9442],{},"Everything is code. Everything is version controlled. Everything is reviewable.",[284,9444,9446],{"className":1181,"code":9445,"language":1183,"meta":289,"style":289},"// Pulumi infrastructure definition (TypeScript)\nimport * as pulumi from '@pulumi/pulumi';\nimport * as aws from '@pulumi/aws';\nimport * as k8s from '@pulumi/kubernetes';\n\nconst vpc = new aws.ec2.Vpc('main', {\n  cidrBlock: '10.0.0.0/16',\n  enableDnsHostnames: true,\n  tags: { Environment: pulumi.getStack() },\n});\n\nconst cluster = new aws.eks.Cluster('platform', {\n  vpcConfig: {\n    subnetIds: subnets.map((s) => s.id),\n    securityGroupIds: [securityGroup.id],\n  },\n  version: '1.29',\n});\n\nconst namespace = new k8s.core.v1.Namespace('services', {\n  metadata: { name: 'services' },\n}, { provider: k8sProvider });\n",[291,9447,9448,9453,9472,9490,9508,9512,9537,9547,9556,9566,9570,9574,9598,9603,9622,9627,9631,9641,9645,9649,9673,9682],{"__ignoreMap":289},[294,9449,9450],{"class":296,"line":297},[294,9451,9452],{"class":300},"// Pulumi infrastructure definition (TypeScript)\n",[294,9454,9455,9457,9459,9462,9465,9467,9470],{"class":296,"line":304},[294,9456,1196],{"class":1195},[294,9458,1784],{"class":315},[294,9460,9461],{"class":1195}," as",[294,9463,9464],{"class":311}," pulumi ",[294,9466,1202],{"class":1195},[294,9468,9469],{"class":336}," '@pulumi/pulumi'",[294,9471,1208],{"class":311},[294,9473,9474,9476,9478,9480,9483,9485,9488],{"class":296,"line":319},[294,9475,1196],{"class":1195},[294,9477,1784],{"class":315},[294,9479,9461],{"class":1195},[294,9481,9482],{"class":311}," aws ",[294,9484,1202],{"class":1195},[294,9486,9487],{"class":336}," '@pulumi/aws'",[294,9489,1208],{"class":311},[294,9491,9492,9494,9496,9498,9501,9503,9506],{"class":296,"line":328},[294,9493,1196],{"class":1195},[294,9495,1784],{"class":315},[294,9497,9461],{"class":1195},[294,9499,9500],{"class":311}," k8s ",[294,9502,1202],{"class":1195},[294,9504,9505],{"class":336}," '@pulumi/kubernetes'",[294,9507,1208],{"class":311},[294,9509,9510],{"class":296,"line":340},[294,9511,366],{"emptyLinePlaceholder":365},[294,9513,9514,9516,9519,9521,9523,9526,9529,9531,9534],{"class":296,"line":351},[294,9515,1217],{"class":1195},[294,9517,9518],{"class":315}," vpc",[294,9520,1223],{"class":1195},[294,9522,1226],{"class":1195},[294,9524,9525],{"class":311}," aws.ec2.",[294,9527,9528],{"class":1112},"Vpc",[294,9530,1270],{"class":311},[294,9532,9533],{"class":336},"'main'",[294,9535,9536],{"class":311},", {\n",[294,9538,9539,9542,9545],{"class":296,"line":362},[294,9540,9541],{"class":311},"  cidrBlock: ",[294,9543,9544],{"class":336},"'10.0.0.0/16'",[294,9546,1243],{"class":311},[294,9548,9549,9552,9554],{"class":296,"line":369},[294,9550,9551],{"class":311},"  enableDnsHostnames: ",[294,9553,2741],{"class":315},[294,9555,1243],{"class":311},[294,9557,9558,9561,9564],{"class":296,"line":377},[294,9559,9560],{"class":311},"  tags: { Environment: pulumi.",[294,9562,9563],{"class":1112},"getStack",[294,9565,4697],{"class":311},[294,9567,9568],{"class":296,"line":385},[294,9569,1258],{"class":311},[294,9571,9572],{"class":296,"line":393},[294,9573,366],{"emptyLinePlaceholder":365},[294,9575,9576,9578,9581,9583,9585,9588,9591,9593,9596],{"class":296,"line":404},[294,9577,1217],{"class":1195},[294,9579,9580],{"class":315}," cluster",[294,9582,1223],{"class":1195},[294,9584,1226],{"class":1195},[294,9586,9587],{"class":311}," aws.eks.",[294,9589,9590],{"class":1112},"Cluster",[294,9592,1270],{"class":311},[294,9594,9595],{"class":336},"'platform'",[294,9597,9536],{"class":311},[294,9599,9600],{"class":296,"line":415},[294,9601,9602],{"class":311},"  vpcConfig: {\n",[294,9604,9605,9608,9610,9612,9615,9617,9619],{"class":296,"line":423},[294,9606,9607],{"class":311},"    subnetIds: subnets.",[294,9609,2796],{"class":1112},[294,9611,2771],{"class":311},[294,9613,9614],{"class":1376},"s",[294,9616,1380],{"class":311},[294,9618,1279],{"class":1195},[294,9620,9621],{"class":311}," s.id),\n",[294,9623,9624],{"class":296,"line":432},[294,9625,9626],{"class":311},"    securityGroupIds: [securityGroup.id],\n",[294,9628,9629],{"class":296,"line":440},[294,9630,1922],{"class":311},[294,9632,9633,9636,9639],{"class":296,"line":451},[294,9634,9635],{"class":311},"  version: ",[294,9637,9638],{"class":336},"'1.29'",[294,9640,1243],{"class":311},[294,9642,9643],{"class":296,"line":459},[294,9644,1258],{"class":311},[294,9646,9647],{"class":296,"line":467},[294,9648,366],{"emptyLinePlaceholder":365},[294,9650,9651,9653,9656,9658,9660,9663,9666,9668,9671],{"class":296,"line":475},[294,9652,1217],{"class":1195},[294,9654,9655],{"class":315}," namespace",[294,9657,1223],{"class":1195},[294,9659,1226],{"class":1195},[294,9661,9662],{"class":311}," k8s.core.v1.",[294,9664,9665],{"class":1112},"Namespace",[294,9667,1270],{"class":311},[294,9669,9670],{"class":336},"'services'",[294,9672,9536],{"class":311},[294,9674,9675,9678,9680],{"class":296,"line":486},[294,9676,9677],{"class":311},"  metadata: { name: ",[294,9679,9670],{"class":336},[294,9681,2744],{"class":311},[294,9683,9684],{"class":296,"line":494},[294,9685,9686],{"class":311},"}, { provider: k8sProvider });\n",[1162,9688,9690],{"type":9689},"warning",[19,9691,9692],{},"Never store secrets in your IaC definitions. Use a dedicated secrets manager (AWS Secrets Manager, HashiCorp Vault) with dynamic secret rotation.",[14,9694,9696],{"id":9695},"the-cost-of-getting-it-wrong","The Cost of Getting It Wrong",[19,9698,9699],{},"We've seen enterprises spend millions on \"cloud migration\" that's really just lift-and-shift — running the same monolith on EC2 instead of bare metal. The result? Higher costs, same fragility, new complexity.",[19,9701,9702],{},"True cloud-native transformation requires:",[1711,9704,9705,9711,9717,9723],{},[50,9706,9707,9710],{},[23,9708,9709],{},"Decomposing the monolith"," along business domain boundaries (not technical layers)",[50,9712,9713,9716],{},[23,9714,9715],{},"Embracing eventual consistency"," where strong consistency isn't required",[50,9718,9719,9722],{},[23,9720,9721],{},"Investing in platform engineering"," so application teams can self-serve",[50,9724,9725,9728],{},[23,9726,9727],{},"Building a culture of ownership"," where teams own their services end-to-end",[14,9730,9732],{"id":9731},"real-world-results","Real-World Results",[19,9734,9735],{},"For a recent financial services client, our cloud-native replatforming delivered:",[124,9737,9738,9750],{},[127,9739,9740],{},[130,9741,9742,9744,9747],{},[133,9743,3442],{},[133,9745,9746],{},"Before",[133,9748,9749],{},"After",[143,9751,9752,9763,9774,9785],{},[130,9753,9754,9757,9760],{},[148,9755,9756],{},"Deploy frequency",[148,9758,9759],{},"Weekly",[148,9761,9762],{},"47x daily",[130,9764,9765,9768,9771],{},[148,9766,9767],{},"Lead time for changes",[148,9769,9770],{},"3 weeks",[148,9772,9773],{},"45 minutes",[130,9775,9776,9779,9782],{},[148,9777,9778],{},"Change failure rate",[148,9780,9781],{},"23%",[148,9783,9784],{},"1.8%",[130,9786,9787,9790,9793],{},[148,9788,9789],{},"Mean time to recovery",[148,9791,9792],{},"4 hours",[148,9794,9795],{},"8 minutes",[19,9797,9798],{},"These aren't theoretical improvements. They're the difference between a company that reacts to market changes and one that drives them.",[2357,9800],{},[19,9802,9803],{},[2180,9804,9805,9806,4250],{},"Ready to modernise your infrastructure? ",[230,9807,9808],{"href":2366},"Let's architect your cloud-native future",[2370,9810,9811],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":289,"searchDepth":304,"depth":304,"links":9813},[9814,9815,9820,9821,9822],{"id":8659,"depth":304,"text":8660},{"id":8666,"depth":304,"text":8667,"children":9816},[9817,9818,9819],{"id":8670,"depth":319,"text":8671},{"id":9371,"depth":319,"text":9372},{"id":9406,"depth":319,"text":9407},{"id":9438,"depth":304,"text":9439},{"id":9695,"depth":304,"text":9696},{"id":9731,"depth":304,"text":9732},"2026-02-05","A deep dive into the architectural patterns and practices that enable enterprise applications to scale globally while maintaining reliability and performance.",{},"/blog/cloud-native-architecture","10 min read",{"title":8651,"description":9824},"blog/cloud-native-architecture",[9831,9832,2419,5068],"Cloud Native","Kubernetes","Dai7RhZjlbZ0dr9DAwJlAIRurZr3eGCVoknlYA4NHXE",1784192087966]