[{"data":1,"prerenderedAt":656},["ShallowReactive",2],{"docs-nav:en":3,"docs:\u002Fdocs\u002Fbring-your-schema":186},[4],{"title":5,"path":6,"stem":7,"children":8},"Docs","\u002Fdocs","docs",[9,12,16,20,24,28,50,75,120,145],{"title":10,"path":6,"stem":11},"What is Fougere","docs\u002Findex",{"title":13,"path":14,"stem":15},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",{"title":17,"path":18,"stem":19},"An app you already have","\u002Fdocs\u002Fexisting-app","docs\u002F02.existing-app",{"title":21,"path":22,"stem":23},"Bring your schema","\u002Fdocs\u002Fbring-your-schema","docs\u002F03.bring-your-schema",{"title":25,"path":26,"stem":27},"The CLI","\u002Fdocs\u002Fcli","docs\u002F04.cli",{"title":29,"path":30,"stem":31,"children":32,"page":49},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F2.concepts",[33,37,41,45],{"title":34,"path":35,"stem":36},"Philosophy","\u002Fdocs\u002Fconcepts\u002Fphilosophy","docs\u002F2.concepts\u002F1.philosophy",{"title":38,"path":39,"stem":40},"The Frond","\u002Fdocs\u002Fconcepts\u002Ffrond","docs\u002F2.concepts\u002F2.frond",{"title":42,"path":43,"stem":44},"The shortest path","\u002Fdocs\u002Fconcepts\u002Fshortest-path","docs\u002F2.concepts\u002F3.shortest-path",{"title":46,"path":47,"stem":48},"The base","\u002Fdocs\u002Fconcepts\u002Fthe-base","docs\u002F2.concepts\u002F4.the-base",false,{"title":51,"path":52,"stem":53,"children":54,"page":49},"Schema","\u002Fdocs\u002Fschema","docs\u002F3.schema",[55,59,63,67,71],{"title":56,"path":57,"stem":58},"Entities","\u002Fdocs\u002Fschema\u002Fentities","docs\u002F3.schema\u002F1.entities",{"title":60,"path":61,"stem":62},"Views","\u002Fdocs\u002Fschema\u002Fviews","docs\u002F3.schema\u002F2.views",{"title":64,"path":65,"stem":66},"The identity card","\u002Fdocs\u002Fschema\u002Fcard","docs\u002F3.schema\u002F3.card",{"title":68,"path":69,"stem":70},"Standard Schema","\u002Fdocs\u002Fschema\u002Fstandard-schema","docs\u002F3.schema\u002F4.standard-schema",{"title":72,"path":73,"stem":74},"How a schema moves","\u002Fdocs\u002Fschema\u002Fevolution","docs\u002F3.schema\u002F5.evolution",{"title":76,"path":77,"stem":78,"children":79,"page":49},"Business","\u002Fdocs\u002Fbusiness","docs\u002F4.business",[80,84,88,92,96,100,104,108,112,116],{"title":81,"path":82,"stem":83},"Handlers","\u002Fdocs\u002Fbusiness\u002Fhandlers","docs\u002F4.business\u002F1.handlers",{"title":85,"path":86,"stem":87},"Ports","\u002Fdocs\u002Fbusiness\u002Fports","docs\u002F4.business\u002F10.ports",{"title":89,"path":90,"stem":91},"Presenters","\u002Fdocs\u002Fbusiness\u002Fpresenters","docs\u002F4.business\u002F2.presenters",{"title":93,"path":94,"stem":95},"Collectors","\u002Fdocs\u002Fbusiness\u002Fcollectors","docs\u002F4.business\u002F3.collectors",{"title":97,"path":98,"stem":99},"Errors","\u002Fdocs\u002Fbusiness\u002Ferrors","docs\u002F4.business\u002F4.errors",{"title":101,"path":102,"stem":103},"Seeds","\u002Fdocs\u002Fbusiness\u002Fseeds","docs\u002F4.business\u002F5.seeds",{"title":105,"path":106,"stem":107},"Facts","\u002Fdocs\u002Fbusiness\u002Ffacts","docs\u002F4.business\u002F6.facts",{"title":109,"path":110,"stem":111},"Storage","\u002Fdocs\u002Fbusiness\u002Fstorage","docs\u002F4.business\u002F7.storage",{"title":113,"path":114,"stem":115},"Writes that stand or fall as one","\u002Fdocs\u002Fbusiness\u002Ftogether","docs\u002F4.business\u002F8.together",{"title":117,"path":118,"stem":119},"Repositories","\u002Fdocs\u002Fbusiness\u002Frepositories","docs\u002F4.business\u002F9.repositories",{"title":121,"path":122,"stem":123,"children":124,"page":49},"Client","\u002Fdocs\u002Fclient","docs\u002F5.client",[125,129,133,137,141],{"title":126,"path":127,"stem":128},"Queries & commands","\u002Fdocs\u002Fclient\u002Fqueries-commands","docs\u002F5.client\u002F1.queries-commands",{"title":130,"path":131,"stem":132},"Forms","\u002Fdocs\u002Fclient\u002Fforms","docs\u002F5.client\u002F2.forms",{"title":134,"path":135,"stem":136},"Session","\u002Fdocs\u002Fclient\u002Fsession","docs\u002F5.client\u002F3.session",{"title":138,"path":139,"stem":140},"invoke","\u002Fdocs\u002Fclient\u002Finvoke","docs\u002F5.client\u002F4.invoke",{"title":142,"path":143,"stem":144},"Back-office","\u002Fdocs\u002Fclient\u002Fadmin","docs\u002F5.client\u002F5.admin",{"title":146,"path":147,"stem":148,"children":149,"page":49},"Infrastructure","\u002Fdocs\u002Finfra","docs\u002F6.infra",[150,154,158,162,166,170,174,178,182],{"title":151,"path":152,"stem":153},"The gradient","\u002Fdocs\u002Finfra\u002Fgradient","docs\u002F6.infra\u002F1.gradient",{"title":155,"path":156,"stem":157},"Surfaces — REST & GraphQL","\u002Fdocs\u002Finfra\u002Fsurfaces","docs\u002F6.infra\u002F2.surfaces",{"title":159,"path":160,"stem":161},"Deployment","\u002Fdocs\u002Finfra\u002Fdeployment","docs\u002F6.infra\u002F3.deployment",{"title":163,"path":164,"stem":165},"Hosts","\u002Fdocs\u002Finfra\u002Fhosts","docs\u002F6.infra\u002F4.hosts",{"title":167,"path":168,"stem":169},"Sources","\u002Fdocs\u002Finfra\u002Fsources","docs\u002F6.infra\u002F5.sources",{"title":171,"path":172,"stem":173},"Lifecycle","\u002Fdocs\u002Finfra\u002Flifecycle","docs\u002F6.infra\u002F6.lifecycle",{"title":175,"path":176,"stem":177},"Identity across Fronds","\u002Fdocs\u002Finfra\u002Fidentity","docs\u002F6.infra\u002F7.identity",{"title":179,"path":180,"stem":181},"Observability","\u002Fdocs\u002Finfra\u002Fobservability","docs\u002F6.infra\u002F8.observability",{"title":183,"path":184,"stem":185},"Testing","\u002Fdocs\u002Finfra\u002Ftesting","docs\u002F6.infra\u002F9.testing",{"id":187,"title":21,"body":188,"description":650,"extension":651,"meta":652,"navigation":653,"path":22,"seo":654,"stem":23,"__hash__":655},"docs_en\u002Fdocs\u002F03.bring-your-schema.md",{"type":189,"value":190,"toc":642},"minimark",[191,195,208,215,220,223,245,255,259,490,507,511,518,578,589,595,602,606,636],[192,193,21],"h1",{"id":194},"bring-your-schema",[196,197,198,199,203,204,207],"p",{},"The previous page is additive about the ",[200,201,202],"strong",{},"host",": your routing, your pages, your rendering\nand your other server routes are untouched. It is not additive about the ",[200,205,206],{},"domain",". The\nentity is the one thing Fougere must own, because it is the one thing everything else is\nderived from.",[196,209,210,211,214],{},"So adopting Fougere has exactly one cost, and this page is it: ",[200,212,213],{},"you declare your model in\nits vocabulary",". What follows is how to keep that cost small, bounded, and paid one entity\nat a time.",[216,217,219],"h2",{"id":218},"one-entity-at-a-time","One entity at a time",[196,221,222],{},"You do not convert a domain. You convert an entity.",[196,224,225,229,230,233,234,233,237,240,241,244],{},[226,227,228],"code",{},"migrate()"," is additive: it emits ",[226,231,232],{},"createTable",", ",[226,235,236],{},"addColumn",[226,238,239],{},"addConstraint"," and\n",[226,242,243],{},"createIndex",", and nothing else. It never drops a column, never rewrites a type, and never\nproposes anything for a table no entity declares. A Fougere entity therefore creates its\nown table beside the ones your current storage manages, in the same database, and your existing\nrows are out of its reach.",[196,246,247,248,250,251,254],{},"The case to watch is a name collision: an entity whose table already exists gets ",[226,249,236],{},"\nproposed ",[200,252,253],{},"on your table"," rather than a fresh one. Rename one of the two, or hand the table\nover on purpose.",[216,256,258],{"id":257},"the-mapping","The mapping",[260,261,262,275],"table",{},[263,264,265],"thead",{},[266,267,268,272],"tr",{},[269,270,271],"th",{},"Prisma",[269,273,274],{},"Fougere",[276,277,278,296,313,328,340,352,364,376,388,405,417,430,441,453,465,478],"tbody",{},[266,279,280,286],{},[281,282,283],"td",{},[226,284,285],{},"String",[281,287,288,291,292,295],{},[226,289,290],{},"text()"," — with ",[226,293,294],{},"{ min, max }"," when you have a rule",[266,297,298,303],{},[281,299,300],{},[226,301,302],{},"String?",[281,304,305,308,309,312],{},[226,306,307],{},"optional(text())",", or ",[226,310,311],{},"nullable(text())"," if the column is truly nullable",[266,314,315,323],{},[281,316,317,233,320],{},[226,318,319],{},"Int",[226,321,322],{},"Float",[281,324,325],{},[226,326,327],{},"number()",[266,329,330,335],{},[281,331,332],{},[226,333,334],{},"Boolean",[281,336,337],{},[226,338,339],{},"bool()",[266,341,342,347],{},[281,343,344],{},[226,345,346],{},"DateTime",[281,348,349],{},[226,350,351],{},"date()",[266,353,354,359],{},[281,355,356],{},[226,357,358],{},"Json",[281,360,361],{},[226,362,363],{},"json()",[266,365,366,371],{},[281,367,368],{},[226,369,370],{},"String @id @default(cuid())",[281,372,373],{},[226,374,375],{},"primary()",[266,377,378,383],{},[281,379,380],{},[226,381,382],{},"@unique",[281,384,385],{},[226,386,387],{},"unique(field)",[266,389,390,395],{},[281,391,392],{},[226,393,394],{},"@@unique([listId, docId])",[281,396,397,400,401,404],{},[226,398,399],{},"unique: [['listId', 'docId']]",", in ",[226,402,403],{},"entity()","'s second argument",[266,406,407,412],{},[281,408,409],{},[226,410,411],{},"@index",[281,413,414],{},[226,415,416],{},"indexed(field)",[266,418,419,425],{},[281,420,421,422],{},"a foreign key + ",[226,423,424],{},"@relation",[281,426,427],{},[226,428,429],{},"ref(Author)",[266,431,432,435],{},[281,433,434],{},"the reverse side of that relation",[281,436,437,440],{},[226,438,439],{},"many(Post)"," — a role, no column",[266,442,443,448],{},[281,444,445],{},[226,446,447],{},"@default(now())",[281,449,450],{},[226,451,452],{},"created()",[266,454,455,460],{},[281,456,457],{},[226,458,459],{},"@updatedAt",[281,461,462],{},[226,463,464],{},"updated()",[266,466,467,473],{},[281,468,469,470],{},"an enum + ",[226,471,472],{},"@default(\"draft\")",[281,474,475],{},[226,476,477],{},"oneOf('draft', 'published', { default: 'draft' })",[266,479,480,485],{},[281,481,482],{},[226,483,484],{},"@db.VarChar(160)",[281,486,487],{},[226,488,489],{},"text({ max: 160 })",[196,491,492,493,495,496,498,499,502,503,506],{},"The last row is the whole thesis in one line. ",[226,494,484],{}," names a dialect;\n",[226,497,489],{}," names the rule, and the dialect is derived from it — along with the\n",[226,500,501],{},"CHECK",", the JSON Schema, the GraphQL type and the form's ",[226,504,505],{},"maxlength",".",[216,508,510],{"id":509},"what-has-no-equivalent","What has no equivalent",[196,512,513,514,517],{},"A Prisma model says what the column ",[200,515,516],{},"is",". That is one of four axes. The other three have\nno column to map from, and they are why the conversion is not mechanical:",[519,520,521,541,557],"ul",{},[522,523,524,530,531,533,534,536,537,540],"li",{},[200,525,526,529],{},[226,527,528],{},"lifecycle"," — who writes the value, and when."," ",[226,532,452],{}," is not ",[226,535,447],{},"\nwith a nicer name: it also states that the value cannot be rewritten on update.\n",[226,538,539],{},"readOnly(oneOf(…))"," states that the client never supplies it at all.",[522,542,543,530,549,552,553,556],{},[200,544,545,548],{},[226,546,547],{},"boundary"," — who may see it.",[226,550,551],{},"writeOnly()"," for the password that goes in and never\ncomes out. ",[226,554,555],{},"readOnly()"," for the field the server stamps.",[522,558,559,530,565,233,568,233,571,233,574,577],{},[200,560,561,564],{},[226,562,563],{},"role"," — what part it plays.",[226,566,567],{},"primary",[226,569,570],{},"ref",[226,572,573],{},"many",[226,575,576],{},"unique"," — read by the DDL for\nkeys and constraints, and by the card for relations.",[196,579,580,581,584,585,588],{},"You enforce all three today. They live in a service method, a DTO, a ",[226,582,583],{},"select:"," clause, an\n",[226,586,587],{},"@Exclude()"," decorator, a review comment. They are real rules with no single home.",[590,591,592],"blockquote",{},[196,593,594],{},"The conversion is not mechanical because you are writing down, for the first time, rules\nyou were already applying.",[196,596,597,598,601],{},"That is the work, and it is also the return: from that declaration the validator, the\ntable, the GraphQL type, the REST route and the form contract are all projections — see\n",[599,600,56],"a",{"href":57}," for the four axes in full.",[216,603,605],{"id":604},"what-stays-where-it-is","What stays where it is",[519,607,608,614,624],{},[522,609,610,613],{},[200,611,612],{},"Your storage."," Fougere claims no ownership of it. In the routes you have not converted,\nkeep querying exactly as you do now.",[522,615,616,619,620,623],{},[200,617,618],{},"Unconverted tables."," Nothing at boot requires the whole database to be declared. The\nscan finds what is in ",[226,621,622],{},"entities\u002F",", and is silent about the rest.",[522,625,626,530,629,632,633,506],{},[200,627,628],{},"Raw statements on a converted entity.",[226,630,631],{},"storage.client"," is the escape hatch on the storage\nport — the underlying Kysely instance for the SQL adapter, scoped to that entity's own\ndata. It is the one path the judge does not sit on; see\n",[599,634,109],{"href":635},"\u002Fdocs\u002Fbusiness\u002Fstorage#client--and-what-it-costs",[196,637,638,639,641],{},"Next: ",[599,640,25],{"href":26}," — composing a workspace, hosting one Frond, calling an operation.",{"title":643,"searchDepth":644,"depth":644,"links":645},"",2,[646,647,648,649],{"id":218,"depth":644,"text":219},{"id":257,"depth":644,"text":258},{"id":509,"depth":644,"text":510},{"id":604,"depth":644,"text":605},"What a Prisma or Drizzle model becomes — and the part you write down for the first time.","md",{},true,{"title":21,"description":650},"3-NN6bieAl05tOP4MWYziNjjkjYMwRapz4hSvSQqkOg",1788560230169]