[{"data":1,"prerenderedAt":851},["ShallowReactive",2],{"navigation_docs":3,"-apps-persistence-multi-tenancy":196,"-apps-persistence-multi-tenancy-surround":846},[4,127,166],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":36},"Kinotic Apps","i-lucide-rocket","\u002Fapps","1.apps",[10,14,18,37,58,91,106,122],{"title":11,"path":12,"stem":13},"Introduction","\u002Fapps\u002Fintroduction","1.apps\u002F1.introduction",{"title":15,"path":16,"stem":17},"Quick Start","\u002Fapps\u002Fquick-start","1.apps\u002F2.quick-start",{"title":19,"icon":20,"path":21,"stem":22,"children":23,"page":36},"Application Structure","i-lucide-folder-tree","\u002Fapps\u002Fapplication-structure","1.apps\u002F3.application-structure",[24,28,32],{"title":25,"path":26,"stem":27},"Overview","\u002Fapps\u002Fapplication-structure\u002Foverview","1.apps\u002F3.application-structure\u002F1.overview",{"title":29,"path":30,"stem":31},"Applications and Projects","\u002Fapps\u002Fapplication-structure\u002Fapplications-and-projects","1.apps\u002F3.application-structure\u002F2.applications-and-projects",{"title":33,"path":34,"stem":35},"Artifact Types","\u002Fapps\u002Fapplication-structure\u002Fartifact-types","1.apps\u002F3.application-structure\u002F3.artifact-types",false,{"title":38,"icon":39,"path":40,"stem":41,"children":42,"page":36},"Services","i-lucide-network","\u002Fapps\u002Fservices","1.apps\u002F4.services",[43,46,50,54],{"title":25,"path":44,"stem":45},"\u002Fapps\u002Fservices\u002Foverview","1.apps\u002F4.services\u002F1.overview",{"title":47,"path":48,"stem":49},"Publishing Services","\u002Fapps\u002Fservices\u002Fpublishing-services","1.apps\u002F4.services\u002F2.publishing-services",{"title":51,"path":52,"stem":53},"Service Proxies","\u002Fapps\u002Fservices\u002Fservice-proxies","1.apps\u002F4.services\u002F3.service-proxies",{"title":55,"path":56,"stem":57},"Streaming","\u002Fapps\u002Fservices\u002Fstreaming","1.apps\u002F4.services\u002F4.streaming",{"title":59,"icon":60,"path":61,"stem":62,"children":63,"page":36},"Persistence","i-lucide-database","\u002Fapps\u002Fpersistence","1.apps\u002F5.persistence",[64,67,71,75,79,83,87],{"title":25,"path":65,"stem":66},"\u002Fapps\u002Fpersistence\u002Foverview","1.apps\u002F5.persistence\u002F1.overview",{"title":68,"path":69,"stem":70},"Defining Entities","\u002Fapps\u002Fpersistence\u002Fdefining-entities","1.apps\u002F5.persistence\u002F2.defining-entities",{"title":72,"path":73,"stem":74},"Entity Decorators","\u002Fapps\u002Fpersistence\u002Fentity-decorators","1.apps\u002F5.persistence\u002F3.entity-decorators",{"title":76,"path":77,"stem":78},"CRUD Operations","\u002Fapps\u002Fpersistence\u002Fcrud-operations","1.apps\u002F5.persistence\u002F4.crud-operations",{"title":80,"path":81,"stem":82},"Named Queries","\u002Fapps\u002Fpersistence\u002Fnamed-queries","1.apps\u002F5.persistence\u002F5.named-queries",{"title":84,"path":85,"stem":86},"Multi-Tenancy","\u002Fapps\u002Fpersistence\u002Fmulti-tenancy","1.apps\u002F5.persistence\u002F6.multi-tenancy",{"title":88,"path":89,"stem":90},"Migrations","\u002Fapps\u002Fpersistence\u002Fmigrations","1.apps\u002F5.persistence\u002F7.migrations",{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":36},"Security","i-lucide-shield-check","\u002Fapps\u002Fsecurity","1.apps\u002F6.security",[97,101],{"title":98,"path":99,"stem":100,"icon":93},"Access Control","\u002Fapps\u002Fsecurity\u002Faccess-control","1.apps\u002F6.security\u002F1.access-control",{"title":102,"path":103,"stem":104,"icon":105},"Authentication","\u002Fapps\u002Fsecurity\u002Fauthentication","1.apps\u002F6.security\u002F2.authentication","i-lucide-key-round",{"title":107,"icon":108,"path":109,"stem":110,"children":111,"page":36},"Deployment","i-lucide-cloud-upload","\u002Fapps\u002Fdeployment","1.apps\u002F7.deployment",[112,117],{"title":113,"path":114,"stem":115,"icon":116},"Deployment Workflow","\u002Fapps\u002Fdeployment\u002Fworkflow","1.apps\u002F7.deployment\u002F1.workflow","i-lucide-git-branch",{"title":118,"path":119,"stem":120,"icon":121},"Environments","\u002Fapps\u002Fdeployment\u002Fenvironments","1.apps\u002F7.deployment\u002F2.environments","i-lucide-server",{"title":123,"path":124,"stem":125,"icon":126},"CLI Reference","\u002Fapps\u002Fcli-reference","1.apps\u002F8.cli-reference","i-lucide-terminal",{"title":128,"icon":121,"path":129,"stem":130,"children":131,"page":36},"Kinotic OS","\u002Fplatform","2.platform",[132,137,141,146,151,156,161],{"title":133,"path":134,"stem":135,"icon":136},"System Architecture","\u002Fplatform\u002Farchitecture","2.platform\u002F1.architecture","i-lucide-boxes",{"title":138,"path":139,"stem":140,"icon":6},"Deployment Guide","\u002Fplatform\u002Fdeployment-guide","2.platform\u002F2.deployment-guide",{"title":142,"path":143,"stem":144,"icon":145},"Configuration","\u002Fplatform\u002Fconfiguration","2.platform\u002F3.configuration","i-lucide-settings",{"title":147,"path":148,"stem":149,"icon":150},"Organization Management","\u002Fplatform\u002Forganization-management","2.platform\u002F4.organization-management","i-lucide-building-2",{"title":152,"path":153,"stem":154,"icon":155},"System Security","\u002Fplatform\u002Fsystem-security","2.platform\u002F5.system-security","i-lucide-shield",{"title":157,"path":158,"stem":159,"icon":160},"Observability","\u002Fplatform\u002Fobservability","2.platform\u002F6.observability","i-lucide-activity",{"title":162,"path":163,"stem":164,"icon":165},"Contributing","\u002Fplatform\u002Fcontributing","2.platform\u002F7.contributing","i-lucide-git-pull-request",{"title":167,"icon":168,"path":169,"stem":170,"children":171,"page":36},"Reference","i-lucide-book-open","\u002Freference","3.reference",[172,177,181,186,191],{"title":173,"path":174,"stem":175,"icon":176},"Decorators Reference","\u002Freference\u002Fdecorators","3.reference\u002F1.decorators","i-lucide-at-sign",{"title":178,"path":179,"stem":180,"icon":60},"Migration SQL Grammar","\u002Freference\u002Fmigration-sql-grammar","3.reference\u002F2.migration-sql-grammar",{"title":182,"path":183,"stem":184,"icon":185},"ABAC Expression Language","\u002Freference\u002Fabac-expression-language","3.reference\u002F3.abac-expression-language","i-lucide-file-code",{"title":187,"path":188,"stem":189,"icon":190},"CRI Format","\u002Freference\u002Fcri-format","3.reference\u002F4.cri-format","i-lucide-link",{"title":192,"path":193,"stem":194,"icon":195},"SDK Packages","\u002Freference\u002Fsdk-packages","3.reference\u002F5.sdk-packages","i-lucide-package",{"id":197,"title":84,"body":198,"description":840,"extension":841,"links":842,"meta":843,"navigation":285,"path":85,"seo":844,"stem":86,"__hash__":845},"docs\u002F1.apps\u002F5.persistence\u002F6.multi-tenancy.md",{"type":199,"value":200,"toc":829},"minimark",[201,205,210,222,423,429,433,440,525,528,532,550,571,576,635,639,694,698,761,765,768,818,822,825],[202,203,204],"p",{},"Kinotic supports multi-tenant data isolation at the persistence layer. Data from different tenants is stored together but automatically filtered so each tenant only sees their own data.",[206,207,209],"h2",{"id":208},"defining-a-multi-tenant-entity","Defining a Multi-Tenant Entity",[202,211,212,213,217,218,221],{},"Add ",[214,215,216],"code",{},"@TenantId"," to a field and set the entity to ",[214,219,220],{},"MultiTenancyType.SHARED",".",[223,224,229],"pre",{"className":225,"code":226,"language":227,"meta":228,"style":228},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Entity, AutoGeneratedId, TenantId, MultiTenancyType } from '@kinotic-ai\u002Fpersistence'\n\n@Entity(MultiTenancyType.SHARED)\nexport class Person {\n    @AutoGeneratedId\n    id: string | null = null\n\n    @TenantId\n    tenantId: string = ''\n\n    firstName: string = ''\n    lastName: string = ''\n}\n","typescript","",[214,230,231,280,287,305,322,331,356,361,369,384,389,403,417],{"__ignoreMap":228},[232,233,236,240,244,248,251,254,256,259,261,264,267,270,273,277],"span",{"class":234,"line":235},"line",1,[232,237,239],{"class":238},"s7zQu","import",[232,241,243],{"class":242},"sMK4o"," {",[232,245,247],{"class":246},"sTEyZ"," Entity",[232,249,250],{"class":242},",",[232,252,253],{"class":246}," AutoGeneratedId",[232,255,250],{"class":242},[232,257,258],{"class":246}," TenantId",[232,260,250],{"class":242},[232,262,263],{"class":246}," MultiTenancyType",[232,265,266],{"class":242}," }",[232,268,269],{"class":238}," from",[232,271,272],{"class":242}," '",[232,274,276],{"class":275},"sfazB","@kinotic-ai\u002Fpersistence",[232,278,279],{"class":242},"'\n",[232,281,283],{"class":234,"line":282},2,[232,284,286],{"emptyLinePlaceholder":285},true,"\n",[232,288,290,293,297,300,302],{"class":234,"line":289},3,[232,291,292],{"class":242},"@",[232,294,296],{"class":295},"s2Zo4","Entity",[232,298,299],{"class":246},"(MultiTenancyType",[232,301,221],{"class":242},[232,303,304],{"class":246},"SHARED)\n",[232,306,308,311,315,319],{"class":234,"line":307},4,[232,309,310],{"class":238},"export",[232,312,314],{"class":313},"spNyl"," class",[232,316,318],{"class":317},"sBMFI"," Person",[232,320,321],{"class":242}," {\n",[232,323,325,328],{"class":234,"line":324},5,[232,326,327],{"class":242},"    @",[232,329,330],{"class":246},"AutoGeneratedId\n",[232,332,334,338,341,344,347,350,353],{"class":234,"line":333},6,[232,335,337],{"class":336},"swJcz","    id",[232,339,340],{"class":242},":",[232,342,343],{"class":317}," string",[232,345,346],{"class":242}," |",[232,348,349],{"class":317}," null",[232,351,352],{"class":242}," =",[232,354,355],{"class":242}," null\n",[232,357,359],{"class":234,"line":358},7,[232,360,286],{"emptyLinePlaceholder":285},[232,362,364,366],{"class":234,"line":363},8,[232,365,327],{"class":242},[232,367,368],{"class":246},"TenantId\n",[232,370,372,375,377,379,381],{"class":234,"line":371},9,[232,373,374],{"class":336},"    tenantId",[232,376,340],{"class":242},[232,378,343],{"class":317},[232,380,352],{"class":242},[232,382,383],{"class":242}," ''\n",[232,385,387],{"class":234,"line":386},10,[232,388,286],{"emptyLinePlaceholder":285},[232,390,392,395,397,399,401],{"class":234,"line":391},11,[232,393,394],{"class":336},"    firstName",[232,396,340],{"class":242},[232,398,343],{"class":317},[232,400,352],{"class":242},[232,402,383],{"class":242},[232,404,406,409,411,413,415],{"class":234,"line":405},12,[232,407,408],{"class":336},"    lastName",[232,410,340],{"class":242},[232,412,343],{"class":317},[232,414,352],{"class":242},[232,416,383],{"class":242},[232,418,420],{"class":234,"line":419},13,[232,421,422],{"class":242},"}\n",[202,424,425,426,428],{},"The ",[214,427,216],{}," field is populated automatically based on the authenticated user's tenant context. You do not need to set it manually when saving entities.",[206,430,432],{"id":431},"tenant-isolated-repository","Tenant-Isolated Repository",[202,434,435,436,439],{},"The standard generated ",[214,437,438],{},"Repository"," automatically filters all operations to the current tenant. No additional configuration is needed.",[223,441,443],{"className":225,"code":442,"language":227,"meta":228,"style":228},"const service = new PersonRepository()\n\n\u002F\u002F Only returns people belonging to the current tenant\nconst people = await service.findAll({ page: 0, size: 10 })\n",[214,444,445,465,469,475],{"__ignoreMap":228},[232,446,447,450,453,456,459,462],{"class":234,"line":235},[232,448,449],{"class":313},"const",[232,451,452],{"class":246}," service ",[232,454,455],{"class":242},"=",[232,457,458],{"class":242}," new",[232,460,461],{"class":295}," PersonRepository",[232,463,464],{"class":246},"()\n",[232,466,467],{"class":234,"line":282},[232,468,286],{"emptyLinePlaceholder":285},[232,470,471],{"class":234,"line":289},[232,472,474],{"class":473},"sHwdD","\u002F\u002F Only returns people belonging to the current tenant\n",[232,476,477,479,482,484,487,490,492,495,498,501,504,506,510,512,515,517,520,522],{"class":234,"line":307},[232,478,449],{"class":313},[232,480,481],{"class":246}," people ",[232,483,455],{"class":242},[232,485,486],{"class":238}," await",[232,488,489],{"class":246}," service",[232,491,221],{"class":242},[232,493,494],{"class":295},"findAll",[232,496,497],{"class":246},"(",[232,499,500],{"class":242},"{",[232,502,503],{"class":336}," page",[232,505,340],{"class":242},[232,507,509],{"class":508},"sbssI"," 0",[232,511,250],{"class":242},[232,513,514],{"class":336}," size",[232,516,340],{"class":242},[232,518,519],{"class":508}," 10",[232,521,266],{"class":242},[232,523,524],{"class":246},")\n",[202,526,527],{},"All CRUD operations (save, find, update, delete, search, count) are scoped to the current tenant transparently.",[206,529,531],{"id":530},"admin-repository","Admin Repository",[202,533,534,535,538,539,541,542,545,546,549],{},"When you run ",[214,536,537],{},"kinotic sync"," on an entity with a ",[214,540,216],{}," field, the CLI generates both a tenant-scoped repository (",[214,543,544],{},"PersonRepository",") and an admin repository (",[214,547,548],{},"PersonAdminRepository",") that can access data across tenants. The admin repository is useful for administrative dashboards, reporting, and cross-tenant operations.",[223,551,553],{"className":225,"code":552,"language":227,"meta":228,"style":228},"const adminService = new PersonAdminRepository()\n",[214,554,555],{"__ignoreMap":228},[232,556,557,559,562,564,566,569],{"class":234,"line":235},[232,558,449],{"class":313},[232,560,561],{"class":246}," adminService ",[232,563,455],{"class":242},[232,565,458],{"class":242},[232,567,568],{"class":295}," PersonAdminRepository",[232,570,464],{"class":246},[572,573,575],"h3",{"id":574},"access-all-tenants","Access All Tenants",[223,577,579],{"className":225,"code":578,"language":227,"meta":228,"style":228},"const allPeople = await adminService.findAll(['*'], { page: 0, size: 10 })\n",[214,580,581],{"__ignoreMap":228},[232,582,583,585,588,590,592,595,597,599,602,605,608,610,613,615,617,619,621,623,625,627,629,631,633],{"class":234,"line":235},[232,584,449],{"class":313},[232,586,587],{"class":246}," allPeople ",[232,589,455],{"class":242},[232,591,486],{"class":238},[232,593,594],{"class":246}," adminService",[232,596,221],{"class":242},[232,598,494],{"class":295},[232,600,601],{"class":246},"([",[232,603,604],{"class":242},"'",[232,606,607],{"class":275},"*",[232,609,604],{"class":242},[232,611,612],{"class":246},"]",[232,614,250],{"class":242},[232,616,243],{"class":242},[232,618,503],{"class":336},[232,620,340],{"class":242},[232,622,509],{"class":508},[232,624,250],{"class":242},[232,626,514],{"class":336},[232,628,340],{"class":242},[232,630,519],{"class":508},[232,632,266],{"class":242},[232,634,524],{"class":246},[572,636,638],{"id":637},"access-a-specific-tenant","Access a Specific Tenant",[223,640,642],{"className":225,"code":641,"language":227,"meta":228,"style":228},"const tenantPeople = await adminService.findAll(['tenant-123'], { page: 0, size: 10 })\n",[214,643,644],{"__ignoreMap":228},[232,645,646,648,651,653,655,657,659,661,663,665,668,670,672,674,676,678,680,682,684,686,688,690,692],{"class":234,"line":235},[232,647,449],{"class":313},[232,649,650],{"class":246}," tenantPeople ",[232,652,455],{"class":242},[232,654,486],{"class":238},[232,656,594],{"class":246},[232,658,221],{"class":242},[232,660,494],{"class":295},[232,662,601],{"class":246},[232,664,604],{"class":242},[232,666,667],{"class":275},"tenant-123",[232,669,604],{"class":242},[232,671,612],{"class":246},[232,673,250],{"class":242},[232,675,243],{"class":242},[232,677,503],{"class":336},[232,679,340],{"class":242},[232,681,509],{"class":508},[232,683,250],{"class":242},[232,685,514],{"class":336},[232,687,340],{"class":242},[232,689,519],{"class":508},[232,691,266],{"class":242},[232,693,524],{"class":246},[572,695,697],{"id":696},"access-multiple-tenants","Access Multiple Tenants",[223,699,701],{"className":225,"code":700,"language":227,"meta":228,"style":228},"const multiPeople = await adminService.findAll(['tenant-123', 'tenant-456'], { page: 0, size: 10 })\n",[214,702,703],{"__ignoreMap":228},[232,704,705,707,710,712,714,716,718,720,722,724,726,728,730,732,735,737,739,741,743,745,747,749,751,753,755,757,759],{"class":234,"line":235},[232,706,449],{"class":313},[232,708,709],{"class":246}," multiPeople ",[232,711,455],{"class":242},[232,713,486],{"class":238},[232,715,594],{"class":246},[232,717,221],{"class":242},[232,719,494],{"class":295},[232,721,601],{"class":246},[232,723,604],{"class":242},[232,725,667],{"class":275},[232,727,604],{"class":242},[232,729,250],{"class":242},[232,731,272],{"class":242},[232,733,734],{"class":275},"tenant-456",[232,736,604],{"class":242},[232,738,612],{"class":246},[232,740,250],{"class":242},[232,742,243],{"class":242},[232,744,503],{"class":336},[232,746,340],{"class":242},[232,748,509],{"class":508},[232,750,250],{"class":242},[232,752,514],{"class":336},[232,754,340],{"class":242},[232,756,519],{"class":508},[232,758,266],{"class":242},[232,760,524],{"class":246},[206,762,764],{"id":763},"tenant-selection","Tenant Selection",[202,766,767],{},"Admin repository methods accept a tenant selection array as the first argument:",[769,770,771,784],"table",{},[772,773,774],"thead",{},[775,776,777,781],"tr",{},[778,779,780],"th",{},"Selection",[778,782,783],{},"Behavior",[785,786,787,798,808],"tbody",{},[775,788,789,795],{},[790,791,792],"td",{},[214,793,794],{},"['*']",[790,796,797],{},"Access data from all tenants",[775,799,800,805],{},[790,801,802],{},[214,803,804],{},"['tenant-123']",[790,806,807],{},"Access data from a single tenant",[775,809,810,815],{},[790,811,812],{},[214,813,814],{},"['tenant-123', 'tenant-456']",[790,816,817],{},"Access data from multiple tenants",[206,819,821],{"id":820},"security-considerations","Security Considerations",[202,823,824],{},"Admin repositories should be restricted to users with appropriate administrative permissions. The standard tenant-isolated repository is the default and should be used for regular application logic.",[826,827,828],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":228,"searchDepth":282,"depth":282,"links":830},[831,832,833,838,839],{"id":208,"depth":282,"text":209},{"id":431,"depth":282,"text":432},{"id":530,"depth":282,"text":531,"children":834},[835,836,837],{"id":574,"depth":289,"text":575},{"id":637,"depth":289,"text":638},{"id":696,"depth":289,"text":697},{"id":763,"depth":282,"text":764},{"id":820,"depth":282,"text":821},"Multi-tenant data isolation in Kinotic with automatic tenant filtering.","md",null,{},{"title":84,"description":840},"xfoTEzYoktrMrTrhT6myO7xytylcgy-KTU_lld2jqh4",[847,849],{"title":80,"path":81,"stem":82,"description":848,"children":-1},"Defining and using custom named queries on entity services in Kinotic.",{"title":88,"path":89,"stem":90,"description":850,"children":-1},"Schema evolution using versioned migration scripts for Kinotic's persistence layer.",1775187765433]