[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"roadmap-build-beginner-backend-nestjs-prisma-supabase-postgres-en":3},{"data":4,"meta":3600},[5],{"id":6,"documentId":7,"title":8,"slug":9,"excerpt":10,"level":11,"durationEstimate":12,"body":13,"createdAt":3403,"updatedAt":3404,"publishedAt":3405,"coverImage":3406,"author":3453,"relatedStacks":3461},30,"tmnc4nr8gwuqscmv1rkb31xj","Build a Beginner Backend with NestJS, Prisma, and Supabase Postgres","build-beginner-backend-nestjs-prisma-supabase-postgres","Learn how to build a beginner-friendly but production-minded backend with NestJS, Prisma, and Supabase Postgres. This roadmap walks through project setup, database design, migrations, seeders, authentication, Swagger docs, and deployment to Render.","beginner","2 to 4 weeks",[14,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,79,83,86,90,94,98,102,106,110,114,117,121,124,128,132,136,140,144,148,152,156,160,164,168,171,175,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,245,249,252,256,260,264,268,272,276,280,284,288,292,295,299,302,306,310,314,318,321,325,328,331,335,338,341,345,348,352,356,359,363,366,370,374,377,381,385,388,392,396,400,404,408,412,415,419,423,426,430,434,438,442,446,450,454,457,461,464,468,472,475,479,482,486,489,493,497,500,503,507,510,514,518,521,524,528,531,534,538,541,545,548,552,555,559,562,565,569,572,575,579,582,585,589,592,596,600,603,606,610,613,617,621,624,628,632,636,640,644,648,652,655,658,662,665,669,673,676,680,683,686,690,693,697,701,704,708,711,715,719,722,726,729,733,737,740,743,747,750,754,758,762,766,770,774,777,781,785,789,792,795,799,803,807,811,815,819,822,826,829,832,836,840,844,848,852,856,860,864,868,872,876,880,884,888,892,895,899,902,905,909,913,917,921,925,929,933,937,941,945,948,952,955,958,962,965,969,973,977,981,985,988,992,996,999,1002,1006,1010,1014,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053,1057,1061,1065,1068,1072,1075,1078,1082,1085,1089,1093,1097,1101,1105,1108,1111,1114,1118,1121,1124,1127,1131,1134,1138,1142,1145,1149,1152,1155,1159,1162,1165,1169,1172,1175,1179,1182,1186,1189,1193,1197,1200,1204,1208,1212,1215,1219,1223,1227,1231,1235,1239,1242,1246,1249,1253,1257,1261,1265,1269,1272,1276,1280,1284,1287,1290,1294,1297,1301,1305,1309,1312,1315,1319,1323,1326,1329,1333,1336,1340,1344,1348,1352,1356,1360,1364,1368,1371,1374,1378,1381,1385,1388,1392,1396,1399,1403,1407,1411,1414,1417,1421,1424,1428,1432,1436,1440,1444,1448,1452,1456,1459,1462,1466,1469,1473,1477,1481,1484,1487,1491,1495,1499,1503,1506,1509,1512,1516,1519,1523,1527,1530,1534,1538,1541,1545,1549,1553,1557,1561,1565,1568,1571,1574,1578,1582,1586,1590,1593,1597,1600,1604,1608,1612,1616,1620,1624,1627,1631,1635,1638,1642,1645,1648,1652,1656,1659,1663,1667,1670,1674,1678,1682,1686,1690,1694,1697,1700,1704,1708,1711,1714,1718,1722,1726,1730,1733,1736,1739,1743,1747,1751,1755,1759,1762,1765,1768,1772,1776,1780,1784,1788,1792,1795,1798,1802,1805,1809,1813,1817,1821,1825,1829,1833,1836,1839,1842,1846,1849,1853,1857,1861,1864,1867,1870,1873,1877,1881,1885,1888,1892,1896,1899,1903,1906,1909,1912,1916,1919,1923,1926,1929,1933,1936,1940,1944,1947,1951,1955,1959,1963,1967,1971,1975,1979,1983,1987,1991,1995,1999,2003,2007,2011,2015,2019,2022,2026,2030,2034,2038,2041,2045,2049,2053,2057,2060,2064,2068,2072,2076,2079,2083,2087,2091,2094,2097,2101,2104,2108,2112,2115,2119,2122,2125,2129,2133,2137,2141,2144,2147,2151,2155,2159,2163,2166,2169,2172,2175,2179,2182,2186,2190,2193,2197,2201,2205,2209,2213,2217,2220,2223,2227,2230,2234,2238,2241,2245,2249,2253,2256,2259,2263,2267,2271,2275,2279,2283,2286,2290,2293,2296,2300,2303,2307,2311,2314,2318,2322,2326,2330,2333,2337,2340,2344,2348,2351,2355,2358,2362,2366,2370,2373,2377,2381,2384,2388,2392,2395,2398,2401,2405,2408,2411,2415,2418,2422,2425,2428,2431,2434,2437,2440,2443,2446,2450,2453,2457,2461,2464,2468,2472,2476,2480,2484,2488,2491,2495,2498,2502,2506,2510,2514,2518,2521,2525,2528,2532,2536,2540,2544,2548,2552,2555,2559,2562,2566,2570,2574,2577,2581,2584,2588,2592,2595,2599,2603,2607,2610,2614,2618,2621,2625,2629,2633,2637,2641,2644,2648,2651,2655,2658,2662,2665,2668,2672,2675,2679,2683,2686,2689,2692,2695,2699,2702,2705,2709,2712,2716,2720,2724,2728,2732,2736,2740,2743,2747,2751,2754,2757,2761,2764,2768,2772,2775,2779,2783,2787,2791,2795,2799,2803,2807,2811,2815,2819,2822,2826,2829,2833,2836,2840,2844,2848,2852,2856,2860,2864,2867,2871,2875,2879,2883,2887,2891,2895,2898,2902,2905,2909,2913,2917,2921,2925,2928,2932,2936,2940,2944,2948,2951,2955,2959,2963,2967,2971,2974,2978,2982,2986,2990,2994,2997,3001,3005,3008,3012,3016,3019,3023,3027,3030,3034,3038,3041,3045,3048,3051,3055,3058,3062,3065,3068,3072,3075,3079,3083,3087,3091,3095,3099,3102,3106,3110,3113,3117,3121,3124,3128,3132,3136,3140,3144,3148,3152,3156,3159,3163,3166,3170,3174,3177,3181,3185,3189,3193,3197,3201,3205,3209,3213,3217,3220,3224,3227,3231,3235,3239,3243,3247,3251,3255,3259,3263,3267,3271,3275,3278,3282,3285,3289,3293,3297,3301,3305,3309,3313,3317,3321,3325,3329,3333,3337,3340,3344,3347,3351,3355,3359,3363,3367,3371,3375,3379,3383,3387,3391,3395,3399],{"type":15,"children":16},"paragraph",[17],{"text":18,"type":19},"## Build a Beginner Backend with NestJS, Prisma, and Supabase Postgres","text",{"type":15,"children":21},[22],{"text":23,"type":19},"",{"type":15,"children":25},[26],{"text":27,"type":19},"### 0. What you are building",{"type":15,"children":29},[30],{"text":31,"type":19},"You will build a small but useful backend called **TaskBoard API**.",{"type":15,"children":33},[34],{"text":35,"type":19},"It will support:",{"type":15,"children":37},[38],{"text":39,"type":19},"* user registration and login",{"type":15,"children":41},[42],{"text":43,"type":19},"* roles (`admin`, `member`)",{"type":15,"children":45},[46],{"text":47,"type":19},"* projects",{"type":15,"children":49},[50],{"text":51,"type":19},"* tasks",{"type":15,"children":53},[54],{"text":55,"type":19},"* comments",{"type":15,"children":57},[58],{"text":59,"type":19},"* task assignment",{"type":15,"children":61},[62],{"text":63,"type":19},"* API documentation",{"type":15,"children":65},[66],{"text":67,"type":19},"* database migrations",{"type":15,"children":69},[70],{"text":71,"type":19},"* seed data",{"type":15,"children":73},[74],{"text":75,"type":19},"* deployment to Render",{"type":15,"children":77},[78],{"text":23,"type":19},{"type":15,"children":80},[81],{"text":82,"type":19},"This is a great beginner backend because it is small enough to finish, but rich enough to teach modules, authentication, relationships, validation, and deployment. Nest’s “first steps” and CLI docs are built around learning the framework through real application structure, not random isolated snippets. ([NestJS Docs][2])",{"type":15,"children":84},[85],{"text":23,"type":19},{"type":15,"children":87},[88],{"text":89,"type":19},"### 1. What the student should know before starting",{"type":15,"children":91},[92],{"text":93,"type":19},"This roadmap is beginner-friendly, but the student should have at least:",{"type":15,"children":95},[96],{"text":97,"type":19},"* basic JavaScript",{"type":15,"children":99},[100],{"text":101,"type":19},"* very basic TypeScript syntax",{"type":15,"children":103},[104],{"text":105,"type":19},"* basic terminal usage",{"type":15,"children":107},[108],{"text":109,"type":19},"* basic idea of what an API is",{"type":15,"children":111},[112],{"text":113,"type":19},"* basic idea of what a database table is",{"type":15,"children":115},[116],{"text":23,"type":19},{"type":15,"children":118},[119],{"text":120,"type":19},"If they do not know these, they can still continue, but they will need to go slowly. Nest is TypeScript-first, and its docs explicitly position TypeScript as a core part of the framework. ([NestJS Docs][3])",{"type":15,"children":122},[123],{"text":23,"type":19},{"type":15,"children":125},[126],{"text":127,"type":19},"### 2. Final stack",{"type":15,"children":129},[130],{"text":131,"type":19},"Use this stack:",{"type":15,"children":133},[134],{"text":135,"type":19},"* **Backend framework:** NestJS",{"type":15,"children":137},[138],{"text":139,"type":19},"* **Language:** TypeScript",{"type":15,"children":141},[142],{"text":143,"type":19},"* **ORM:** Prisma",{"type":15,"children":145},[146],{"text":147,"type":19},"* **Database:** Supabase Postgres",{"type":15,"children":149},[150],{"text":151,"type":19},"* **Authentication:** JWT",{"type":15,"children":153},[154],{"text":155,"type":19},"* **Validation:** class-validator + class-transformer",{"type":15,"children":157},[158],{"text":159,"type":19},"* **Password hashing:** bcrypt",{"type":15,"children":161},[162],{"text":163,"type":19},"* **Docs:** Swagger",{"type":15,"children":165},[166],{"text":167,"type":19},"* **Deployment:** Render",{"type":15,"children":169},[170],{"text":23,"type":19},{"type":15,"children":172},[173],{"text":174,"type":19},"Nest officially supports a CLI workflow for creating and structuring apps, Prisma officially documents seeding and migrations, and Supabase provides Postgres as the database foundation of each project. ([NestJS Docs][1])",{"type":15,"children":176},[177],{"text":23,"type":19},{"type":15,"children":179},[180],{"text":181,"type":19},"### 3. Learning phases",{"type":15,"children":183},[184],{"text":185,"type":19},"This roadmap is best done in this order:",{"type":15,"children":187},[188],{"text":189,"type":19},"1. Environment setup",{"type":15,"children":191},[192],{"text":193,"type":19},"2. Create a Supabase project",{"type":15,"children":195},[196],{"text":197,"type":19},"3. Create the NestJS project",{"type":15,"children":199},[200],{"text":201,"type":19},"4. Configure Prisma",{"type":15,"children":203},[204],{"text":205,"type":19},"5. Design the database",{"type":15,"children":207},[208],{"text":209,"type":19},"6. Create migrations",{"type":15,"children":211},[212],{"text":213,"type":19},"7. Add seeders",{"type":15,"children":215},[216],{"text":217,"type":19},"8. Build authentication",{"type":15,"children":219},[220],{"text":221,"type":19},"9. Build business modules",{"type":15,"children":223},[224],{"text":225,"type":19},"10. Add validation and error handling",{"type":15,"children":227},[228],{"text":229,"type":19},"11. Add Swagger docs",{"type":15,"children":231},[232],{"text":233,"type":19},"12. Test locally",{"type":15,"children":235},[236],{"text":237,"type":19},"13. Prepare for production",{"type":15,"children":239},[240],{"text":241,"type":19},"14. Deploy to Render",{"type":15,"children":243},[244],{"text":23,"type":19},{"type":15,"children":246},[247],{"text":248,"type":19},"That order matters. If you start building controllers before your data model is stable, you are basically building your house roof-first. That always ends in a mess. Nest’s CLI and Prisma’s migration workflow both assume a structured, layered development path. ([NestJS Docs][1])",{"type":15,"children":250},[251],{"text":23,"type":19},{"type":15,"children":253},[254],{"text":255,"type":19},"### 4. Step 1 — Install the required tools",{"type":15,"children":257},[258],{"text":259,"type":19},"Install these first:",{"type":15,"children":261},[262],{"text":263,"type":19},"* **Node.js LTS**",{"type":15,"children":265},[266],{"text":267,"type":19},"* **npm** or another package manager",{"type":15,"children":269},[270],{"text":271,"type":19},"* **Git**",{"type":15,"children":273},[274],{"text":275,"type":19},"* **VS Code**",{"type":15,"children":277},[278],{"text":279,"type":19},"* **Postman** or Insomnia for testing",{"type":15,"children":281},[282],{"text":283,"type":19},"* a **Supabase account**",{"type":15,"children":285},[286],{"text":287,"type":19},"* a **Render account**",{"type":15,"children":289},[290],{"text":291,"type":19},"* optionally **Docker** for local Postgres practice",{"type":15,"children":293},[294],{"text":23,"type":19},{"type":15,"children":296},[297],{"text":298,"type":19},"Nest uses the CLI to generate and maintain projects, and Supabase also offers a CLI for local development, though for this roadmap the hosted Supabase project is enough. ([NestJS Docs][1])",{"type":15,"children":300},[301],{"text":23,"type":19},{"type":15,"children":303},[304],{"text":305,"type":19},"#### Install Nest CLI",{"type":15,"children":307},[308],{"text":309,"type":19},"```bash",{"type":15,"children":311},[312],{"text":313,"type":19},"npm install -g @nestjs/cli",{"type":15,"children":315},[316],{"text":317,"type":19},"```",{"type":15,"children":319},[320],{"text":23,"type":19},{"type":15,"children":322},[323],{"text":324,"type":19},"#### Check that it works",{"type":15,"children":326},[327],{"text":23,"type":19},{"type":15,"children":329},[330],{"text":309,"type":19},{"type":15,"children":332},[333],{"text":334,"type":19},"nest --version",{"type":15,"children":336},[337],{"text":317,"type":19},{"type":15,"children":339},[340],{"text":23,"type":19},{"type":15,"children":342},[343],{"text":344,"type":19},"The Nest CLI is the standard way to scaffold and manage Nest applications. ([NestJS Docs][1])",{"type":15,"children":346},[347],{"text":23,"type":19},{"type":15,"children":349},[350],{"text":351,"type":19},"### 5. Step 2 — Create a Supabase project from scratch",{"type":15,"children":353},[354],{"text":355,"type":19},"This part must be taught slowly, because beginners usually get lost here.",{"type":15,"children":357},[358],{"text":23,"type":19},{"type":15,"children":360},[361],{"text":362,"type":19},"Supabase is a Postgres development platform, and every Supabase project includes a Postgres database. Its docs also direct users to create a new project first before using tables, SQL, or external app connections. ([Supabase][4])",{"type":15,"children":364},[365],{"text":23,"type":19},{"type":15,"children":367},[368],{"text":369,"type":19},"#### 5.1 Go to Supabase",{"type":15,"children":371},[372],{"text":373,"type":19},"Open the Supabase website and sign in.",{"type":15,"children":375},[376],{"text":23,"type":19},{"type":15,"children":378},[379],{"text":380,"type":19},"##### 5.2 Create a new organization",{"type":15,"children":382},[383],{"text":384,"type":19},"If this is the student’s first time, Supabase may ask them to create or select an organization.",{"type":15,"children":386},[387],{"text":23,"type":19},{"type":15,"children":389},[390],{"text":391,"type":19},"##### 5.3 Create a new project",{"type":15,"children":393},[394],{"text":395,"type":19},"Create a new project and fill in:",{"type":15,"children":397},[398],{"text":399,"type":19},"* **Project name:** `taskboard-api`",{"type":15,"children":401},[402],{"text":403,"type":19},"* **Database password:** choose a strong password and save it",{"type":15,"children":405},[406],{"text":407,"type":19},"* **Region:** choose the nearest region to you",{"type":15,"children":409},[410],{"text":411,"type":19},"* **Pricing plan:** free tier if available for learning",{"type":15,"children":413},[414],{"text":23,"type":19},{"type":15,"children":416},[417],{"text":418,"type":19},"##### 5.4 Wait for provisioning",{"type":15,"children":420},[421],{"text":422,"type":19},"The project will take a short while to be created.",{"type":15,"children":424},[425],{"text":23,"type":19},{"type":15,"children":427},[428],{"text":429,"type":19},"##### 5.5 Open the project dashboard",{"type":15,"children":431},[432],{"text":433,"type":19},"Once the project is ready, open it and look for:",{"type":15,"children":435},[436],{"text":437,"type":19},"* **Project Settings**",{"type":15,"children":439},[440],{"text":441,"type":19},"* **Database**",{"type":15,"children":443},[444],{"text":445,"type":19},"* **SQL Editor**",{"type":15,"children":447},[448],{"text":449,"type":19},"* **Table Editor**",{"type":15,"children":451},[452],{"text":453,"type":19},"* **Connect**",{"type":15,"children":455},[456],{"text":23,"type":19},{"type":15,"children":458},[459],{"text":460,"type":19},"Supabase’s documentation revolves around these main dashboard areas for creating projects, working with Postgres, and connecting applications. ([Supabase][5])",{"type":15,"children":462},[463],{"text":23,"type":19},{"type":15,"children":465},[466],{"text":467,"type":19},"##### 5.6 Get the database connection string",{"type":15,"children":469},[470],{"text":471,"type":19},"Inside the project dashboard, go to the database connection area and copy the **Postgres connection string**.",{"type":15,"children":473},[474],{"text":23,"type":19},{"type":15,"children":476},[477],{"text":478,"type":19},"You need the connection string because Prisma connects to Postgres through `DATABASE_URL`. Prisma’s datasource configuration uses a connection URL from the environment. ([NestJS Docs][6])",{"type":15,"children":480},[481],{"text":23,"type":19},{"type":15,"children":483},[484],{"text":485,"type":19},"It will look similar to this:",{"type":15,"children":487},[488],{"text":23,"type":19},{"type":15,"children":490},[491],{"text":492,"type":19},"```env",{"type":15,"children":494},[495],{"text":496,"type":19},"DATABASE_URL=\"postgresql://postgres:[YOUR_PASSWORD]@db.[PROJECT-REF].supabase.co:5432/postgres\"",{"type":15,"children":498},[499],{"text":317,"type":19},{"type":15,"children":501},[502],{"text":23,"type":19},{"type":15,"children":504},[505],{"text":506,"type":19},"Save it carefully. That string is gold. Lose it and you are back in the swamp.",{"type":15,"children":508},[509],{"text":23,"type":19},{"type":15,"children":511},[512],{"text":513,"type":19},"### 6. Step 3 — Create the NestJS project",{"type":15,"children":515},[516],{"text":517,"type":19},"Now create the backend app.",{"type":15,"children":519},[520],{"text":23,"type":19},{"type":15,"children":522},[523],{"text":309,"type":19},{"type":15,"children":525},[526],{"text":527,"type":19},"nest new taskboard-api",{"type":15,"children":529},[530],{"text":317,"type":19},{"type":15,"children":532},[533],{"text":23,"type":19},{"type":15,"children":535},[536],{"text":537,"type":19},"Choose **npm** when prompted if you want the simplest beginner flow.",{"type":15,"children":539},[540],{"text":23,"type":19},{"type":15,"children":542},[543],{"text":544,"type":19},"Nest’s CLI command `nest new` creates a full project folder with source files, test files, and scripts already configured. ([NestJS Docs][7])",{"type":15,"children":546},[547],{"text":23,"type":19},{"type":15,"children":549},[550],{"text":551,"type":19},"Move into the project:",{"type":15,"children":553},[554],{"text":309,"type":19},{"type":15,"children":556},[557],{"text":558,"type":19},"cd taskboard-api",{"type":15,"children":560},[561],{"text":317,"type":19},{"type":15,"children":563},[564],{"text":23,"type":19},{"type":15,"children":566},[567],{"text":568,"type":19},"Start the dev server once just to confirm it runs:",{"type":15,"children":570},[571],{"text":23,"type":19},{"type":15,"children":573},[574],{"text":309,"type":19},{"type":15,"children":576},[577],{"text":578,"type":19},"npm run start:dev",{"type":15,"children":580},[581],{"text":317,"type":19},{"type":15,"children":583},[584],{"text":23,"type":19},{"type":15,"children":586},[587],{"text":588,"type":19},"Then open:",{"type":15,"children":590},[591],{"text":23,"type":19},{"type":15,"children":593},[594],{"text":595,"type":19},"```txt",{"type":15,"children":597},[598],{"text":599,"type":19},"http://localhost:3000",{"type":15,"children":601},[602],{"text":317,"type":19},{"type":15,"children":604},[605],{"text":23,"type":19},{"type":15,"children":607},[608],{"text":609,"type":19},"If you see the default response, good. The engine breathes.",{"type":15,"children":611},[612],{"text":23,"type":19},{"type":15,"children":614},[615],{"text":616,"type":19},"### 7. Step 4 — Install project dependencies",{"type":15,"children":618},[619],{"text":620,"type":19},"Install the database, auth, config, and validation packages.",{"type":15,"children":622},[623],{"text":309,"type":19},{"type":15,"children":625},[626],{"text":627,"type":19},"npm install @prisma/client prisma",{"type":15,"children":629},[630],{"text":631,"type":19},"npm install @nestjs/config",{"type":15,"children":633},[634],{"text":635,"type":19},"npm install @nestjs/jwt @nestjs/passport passport passport-jwt",{"type":15,"children":637},[638],{"text":639,"type":19},"npm install class-validator class-transformer",{"type":15,"children":641},[642],{"text":643,"type":19},"npm install bcrypt",{"type":15,"children":645},[646],{"text":647,"type":19},"npm install @nestjs/swagger swagger-ui-express",{"type":15,"children":649},[650],{"text":651,"type":19},"npm install -D @types/passport-jwt @types/bcrypt ts-node",{"type":15,"children":653},[654],{"text":317,"type":19},{"type":15,"children":656},[657],{"text":23,"type":19},{"type":15,"children":659},[660],{"text":661,"type":19},"These packages match the documented Nest and Prisma workflows for configuration, REST APIs, and seeding. ([NestJS Docs][6])",{"type":15,"children":663},[664],{"text":23,"type":19},{"type":15,"children":666},[667],{"text":668,"type":19},"### 8. Step 5 — Initialize Prisma",{"type":15,"children":670},[671],{"text":672,"type":19},"Run:",{"type":15,"children":674},[675],{"text":309,"type":19},{"type":15,"children":677},[678],{"text":679,"type":19},"npx prisma init",{"type":15,"children":681},[682],{"text":317,"type":19},{"type":15,"children":684},[685],{"text":23,"type":19},{"type":15,"children":687},[688],{"text":689,"type":19},"This creates:",{"type":15,"children":691},[692],{"text":23,"type":19},{"type":15,"children":694},[695],{"text":696,"type":19},"* `prisma/schema.prisma`",{"type":15,"children":698},[699],{"text":700,"type":19},"* an environment file if not already present",{"type":15,"children":702},[703],{"text":23,"type":19},{"type":15,"children":705},[706],{"text":707,"type":19},"Prisma’s workflow starts with initialization, then defining the datasource and models, then migrations and seeding. ([Prisma][8])",{"type":15,"children":709},[710],{"text":23,"type":19},{"type":15,"children":712},[713],{"text":714,"type":19},"### 9. Step 6 — Configure environment variables",{"type":15,"children":716},[717],{"text":718,"type":19},"Create or update your `.env` file:",{"type":15,"children":720},[721],{"text":492,"type":19},{"type":15,"children":723},[724],{"text":725,"type":19},"PORT=3000",{"type":15,"children":727},[728],{"text":496,"type":19},{"type":15,"children":730},[731],{"text":732,"type":19},"JWT_SECRET=\"change-this-secret\"",{"type":15,"children":734},[735],{"text":736,"type":19},"JWT_EXPIRES_IN=\"1d\"",{"type":15,"children":738},[739],{"text":317,"type":19},{"type":15,"children":741},[742],{"text":23,"type":19},{"type":15,"children":744},[745],{"text":746,"type":19},"Nest recommends using `@nestjs/config` for application configuration, and Prisma expects the database URL through the datasource environment variable. ([NestJS Docs][6])",{"type":15,"children":748},[749],{"text":23,"type":19},{"type":15,"children":751},[752],{"text":753,"type":19},"### 10. Step 7 — Configure Prisma schema",{"type":15,"children":755},[756],{"text":757,"type":19},"Open `prisma/schema.prisma` and replace it with this:",{"type":15,"children":759},[760],{"text":761,"type":19},"```prisma",{"type":15,"children":763},[764],{"text":765,"type":19},"generator client {",{"type":15,"children":767},[768],{"text":769,"type":19},"  provider = \"prisma-client-js\"",{"type":15,"children":771},[772],{"text":773,"type":19},"}",{"type":15,"children":775},[776],{"text":23,"type":19},{"type":15,"children":778},[779],{"text":780,"type":19},"datasource db {",{"type":15,"children":782},[783],{"text":784,"type":19},"  provider = \"postgresql\"",{"type":15,"children":786},[787],{"text":788,"type":19},"  url      = env(\"DATABASE_URL\")",{"type":15,"children":790},[791],{"text":773,"type":19},{"type":15,"children":793},[794],{"text":23,"type":19},{"type":15,"children":796},[797],{"text":798,"type":19},"model Role {",{"type":15,"children":800},[801],{"text":802,"type":19},"  id        String   @id @default(uuid()) @db.Uuid",{"type":15,"children":804},[805],{"text":806,"type":19},"  name      String   @unique @db.VarChar(30)",{"type":15,"children":808},[809],{"text":810,"type":19},"  users     User[]",{"type":15,"children":812},[813],{"text":814,"type":19},"  createdAt DateTime @default(now()) @map(\"created_at\")",{"type":15,"children":816},[817],{"text":818,"type":19},"  updatedAt DateTime @updatedAt @map(\"updated_at\")",{"type":15,"children":820},[821],{"text":23,"type":19},{"type":15,"children":823},[824],{"text":825,"type":19},"  @@map(\"roles\")",{"type":15,"children":827},[828],{"text":773,"type":19},{"type":15,"children":830},[831],{"text":23,"type":19},{"type":15,"children":833},[834],{"text":835,"type":19},"model User {",{"type":15,"children":837},[838],{"text":839,"type":19},"  id           String          @id @default(uuid()) @db.Uuid",{"type":15,"children":841},[842],{"text":843,"type":19},"  fullName     String          @map(\"full_name\") @db.VarChar(120)",{"type":15,"children":845},[846],{"text":847,"type":19},"  email        String          @unique @db.VarChar(120)",{"type":15,"children":849},[850],{"text":851,"type":19},"  passwordHash String          @map(\"password_hash\")",{"type":15,"children":853},[854],{"text":855,"type":19},"  roleId       String          @map(\"role_id\") @db.Uuid",{"type":15,"children":857},[858],{"text":859,"type":19},"  isActive     Boolean         @default(true) @map(\"is_active\")",{"type":15,"children":861},[862],{"text":863,"type":19},"  role         Role            @relation(fields: [roleId], references: [id])",{"type":15,"children":865},[866],{"text":867,"type":19},"  ownedProjects Project[]      @relation(\"ProjectOwner\")",{"type":15,"children":869},[870],{"text":871,"type":19},"  memberships  ProjectMember[]",{"type":15,"children":873},[874],{"text":875,"type":19},"  assignedTasks Task[]         @relation(\"TaskAssignee\")",{"type":15,"children":877},[878],{"text":879,"type":19},"  createdTasks Task[]          @relation(\"TaskCreator\")",{"type":15,"children":881},[882],{"text":883,"type":19},"  comments     Comment[]",{"type":15,"children":885},[886],{"text":887,"type":19},"  createdAt    DateTime        @default(now()) @map(\"created_at\")",{"type":15,"children":889},[890],{"text":891,"type":19},"  updatedAt    DateTime        @updatedAt @map(\"updated_at\")",{"type":15,"children":893},[894],{"text":23,"type":19},{"type":15,"children":896},[897],{"text":898,"type":19},"  @@map(\"users\")",{"type":15,"children":900},[901],{"text":773,"type":19},{"type":15,"children":903},[904],{"text":23,"type":19},{"type":15,"children":906},[907],{"text":908,"type":19},"model Project {",{"type":15,"children":910},[911],{"text":912,"type":19},"  id          String          @id @default(uuid()) @db.Uuid",{"type":15,"children":914},[915],{"text":916,"type":19},"  name        String          @db.VarChar(120)",{"type":15,"children":918},[919],{"text":920,"type":19},"  description String?",{"type":15,"children":922},[923],{"text":924,"type":19},"  ownerId     String          @map(\"owner_id\") @db.Uuid",{"type":15,"children":926},[927],{"text":928,"type":19},"  owner       User            @relation(\"ProjectOwner\", fields: [ownerId], references: [id])",{"type":15,"children":930},[931],{"text":932,"type":19},"  members     ProjectMember[]",{"type":15,"children":934},[935],{"text":936,"type":19},"  tasks       Task[]",{"type":15,"children":938},[939],{"text":940,"type":19},"  createdAt   DateTime        @default(now()) @map(\"created_at\")",{"type":15,"children":942},[943],{"text":944,"type":19},"  updatedAt   DateTime        @updatedAt @map(\"updated_at\")",{"type":15,"children":946},[947],{"text":23,"type":19},{"type":15,"children":949},[950],{"text":951,"type":19},"  @@map(\"projects\")",{"type":15,"children":953},[954],{"text":773,"type":19},{"type":15,"children":956},[957],{"text":23,"type":19},{"type":15,"children":959},[960],{"text":961,"type":19},"model ProjectMember {",{"type":15,"children":963},[964],{"text":802,"type":19},{"type":15,"children":966},[967],{"text":968,"type":19},"  projectId String   @map(\"project_id\") @db.Uuid",{"type":15,"children":970},[971],{"text":972,"type":19},"  userId    String   @map(\"user_id\") @db.Uuid",{"type":15,"children":974},[975],{"text":976,"type":19},"  project   Project  @relation(fields: [projectId], references: [id], onDelete: Cascade)",{"type":15,"children":978},[979],{"text":980,"type":19},"  user      User     @relation(fields: [userId], references: [id], onDelete: Cascade)",{"type":15,"children":982},[983],{"text":984,"type":19},"  joinedAt  DateTime @default(now()) @map(\"joined_at\")",{"type":15,"children":986},[987],{"text":23,"type":19},{"type":15,"children":989},[990],{"text":991,"type":19},"  @@unique([projectId, userId])",{"type":15,"children":993},[994],{"text":995,"type":19},"  @@map(\"project_members\")",{"type":15,"children":997},[998],{"text":773,"type":19},{"type":15,"children":1000},[1001],{"text":23,"type":19},{"type":15,"children":1003},[1004],{"text":1005,"type":19},"model Task {",{"type":15,"children":1007},[1008],{"text":1009,"type":19},"  id          String    @id @default(uuid()) @db.Uuid",{"type":15,"children":1011},[1012],{"text":1013,"type":19},"  title       String    @db.VarChar(150)",{"type":15,"children":1015},[1016],{"text":920,"type":19},{"type":15,"children":1018},[1019],{"text":1020,"type":19},"  status      String    @default(\"todo\") @db.VarChar(20)",{"type":15,"children":1022},[1023],{"text":1024,"type":19},"  priority    String    @default(\"medium\") @db.VarChar(20)",{"type":15,"children":1026},[1027],{"text":1028,"type":19},"  projectId   String    @map(\"project_id\") @db.Uuid",{"type":15,"children":1030},[1031],{"text":1032,"type":19},"  assigneeId  String?   @map(\"assignee_id\") @db.Uuid",{"type":15,"children":1034},[1035],{"text":1036,"type":19},"  createdBy   String    @map(\"created_by\") @db.Uuid",{"type":15,"children":1038},[1039],{"text":1040,"type":19},"  dueDate     DateTime? @map(\"due_date\")",{"type":15,"children":1042},[1043],{"text":1044,"type":19},"  project     Project   @relation(fields: [projectId], references: [id], onDelete: Cascade)",{"type":15,"children":1046},[1047],{"text":1048,"type":19},"  assignee    User?     @relation(\"TaskAssignee\", fields: [assigneeId], references: [id], onDelete: SetNull)",{"type":15,"children":1050},[1051],{"text":1052,"type":19},"  creator     User      @relation(\"TaskCreator\", fields: [createdBy], references: [id])",{"type":15,"children":1054},[1055],{"text":1056,"type":19},"  comments    Comment[]",{"type":15,"children":1058},[1059],{"text":1060,"type":19},"  createdAt   DateTime  @default(now()) @map(\"created_at\")",{"type":15,"children":1062},[1063],{"text":1064,"type":19},"  updatedAt   DateTime  @updatedAt @map(\"updated_at\")",{"type":15,"children":1066},[1067],{"text":23,"type":19},{"type":15,"children":1069},[1070],{"text":1071,"type":19},"  @@map(\"tasks\")",{"type":15,"children":1073},[1074],{"text":773,"type":19},{"type":15,"children":1076},[1077],{"text":23,"type":19},{"type":15,"children":1079},[1080],{"text":1081,"type":19},"model Comment {",{"type":15,"children":1083},[1084],{"text":802,"type":19},{"type":15,"children":1086},[1087],{"text":1088,"type":19},"  taskId    String   @map(\"task_id\") @db.Uuid",{"type":15,"children":1090},[1091],{"text":1092,"type":19},"  authorId  String   @map(\"author_id\") @db.Uuid",{"type":15,"children":1094},[1095],{"text":1096,"type":19},"  content   String",{"type":15,"children":1098},[1099],{"text":1100,"type":19},"  task      Task     @relation(fields: [taskId], references: [id], onDelete: Cascade)",{"type":15,"children":1102},[1103],{"text":1104,"type":19},"  author    User     @relation(fields: [authorId], references: [id], onDelete: Cascade)",{"type":15,"children":1106},[1107],{"text":814,"type":19},{"type":15,"children":1109},[1110],{"text":818,"type":19},{"type":15,"children":1112},[1113],{"text":23,"type":19},{"type":15,"children":1115},[1116],{"text":1117,"type":19},"  @@map(\"comments\")",{"type":15,"children":1119},[1120],{"text":773,"type":19},{"type":15,"children":1122},[1123],{"text":317,"type":19},{"type":15,"children":1125},[1126],{"text":23,"type":19},{"type":15,"children":1128},[1129],{"text":1130,"type":19},"This schema is mapped to PostgreSQL via Prisma’s standard datasource model workflow. ([Prisma][8])",{"type":15,"children":1132},[1133],{"text":23,"type":19},{"type":15,"children":1135},[1136],{"text":1137,"type":19},"### 11. Step 8 — Create the first migration",{"type":15,"children":1139},[1140],{"text":1141,"type":19},"Now generate the database tables from Prisma.",{"type":15,"children":1143},[1144],{"text":309,"type":19},{"type":15,"children":1146},[1147],{"text":1148,"type":19},"npx prisma migrate dev --name init",{"type":15,"children":1150},[1151],{"text":317,"type":19},{"type":15,"children":1153},[1154],{"text":23,"type":19},{"type":15,"children":1156},[1157],{"text":1158,"type":19},"Then generate the Prisma client:",{"type":15,"children":1160},[1161],{"text":23,"type":19},{"type":15,"children":1163},[1164],{"text":309,"type":19},{"type":15,"children":1166},[1167],{"text":1168,"type":19},"npx prisma generate",{"type":15,"children":1170},[1171],{"text":317,"type":19},{"type":15,"children":1173},[1174],{"text":23,"type":19},{"type":15,"children":1176},[1177],{"text":1178,"type":19},"Prisma documents migrations as the standard way to evolve the schema and generate the database structure from the Prisma models. ([Prisma][8])",{"type":15,"children":1180},[1181],{"text":23,"type":19},{"type":15,"children":1183},[1184],{"text":1185,"type":19},"If successful, your Supabase Postgres database will now contain the tables.",{"type":15,"children":1187},[1188],{"text":23,"type":19},{"type":15,"children":1190},[1191],{"text":1192,"type":19},"### 12. Step 9 — Show the beginner the raw SQL too",{"type":15,"children":1194},[1195],{"text":1196,"type":19},"This matters. Beginners need to understand that Prisma is not magic dust. It is a layer over SQL, not a replacement for understanding data.",{"type":15,"children":1198},[1199],{"text":23,"type":19},{"type":15,"children":1201},[1202],{"text":1203,"type":19},"Here is the equivalent PostgreSQL SQL schema:",{"type":15,"children":1205},[1206],{"text":1207,"type":19},"```sql",{"type":15,"children":1209},[1210],{"text":1211,"type":19},"CREATE EXTENSION IF NOT EXISTS \"pgcrypto\";",{"type":15,"children":1213},[1214],{"text":23,"type":19},{"type":15,"children":1216},[1217],{"text":1218,"type":19},"CREATE TABLE roles (",{"type":15,"children":1220},[1221],{"text":1222,"type":19},"  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),",{"type":15,"children":1224},[1225],{"text":1226,"type":19},"  name VARCHAR(30) UNIQUE NOT NULL,",{"type":15,"children":1228},[1229],{"text":1230,"type":19},"  created_at TIMESTAMP NOT NULL DEFAULT NOW(),",{"type":15,"children":1232},[1233],{"text":1234,"type":19},"  updated_at TIMESTAMP NOT NULL DEFAULT NOW()",{"type":15,"children":1236},[1237],{"text":1238,"type":19},");",{"type":15,"children":1240},[1241],{"text":23,"type":19},{"type":15,"children":1243},[1244],{"text":1245,"type":19},"CREATE TABLE users (",{"type":15,"children":1247},[1248],{"text":1222,"type":19},{"type":15,"children":1250},[1251],{"text":1252,"type":19},"  full_name VARCHAR(120) NOT NULL,",{"type":15,"children":1254},[1255],{"text":1256,"type":19},"  email VARCHAR(120) UNIQUE NOT NULL,",{"type":15,"children":1258},[1259],{"text":1260,"type":19},"  password_hash TEXT NOT NULL,",{"type":15,"children":1262},[1263],{"text":1264,"type":19},"  role_id UUID NOT NULL,",{"type":15,"children":1266},[1267],{"text":1268,"type":19},"  is_active BOOLEAN NOT NULL DEFAULT TRUE,",{"type":15,"children":1270},[1271],{"text":1230,"type":19},{"type":15,"children":1273},[1274],{"text":1275,"type":19},"  updated_at TIMESTAMP NOT NULL DEFAULT NOW(),",{"type":15,"children":1277},[1278],{"text":1279,"type":19},"  CONSTRAINT fk_users_role",{"type":15,"children":1281},[1282],{"text":1283,"type":19},"    FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE RESTRICT",{"type":15,"children":1285},[1286],{"text":1238,"type":19},{"type":15,"children":1288},[1289],{"text":23,"type":19},{"type":15,"children":1291},[1292],{"text":1293,"type":19},"CREATE TABLE projects (",{"type":15,"children":1295},[1296],{"text":1222,"type":19},{"type":15,"children":1298},[1299],{"text":1300,"type":19},"  name VARCHAR(120) NOT NULL,",{"type":15,"children":1302},[1303],{"text":1304,"type":19},"  description TEXT,",{"type":15,"children":1306},[1307],{"text":1308,"type":19},"  owner_id UUID NOT NULL,",{"type":15,"children":1310},[1311],{"text":1230,"type":19},{"type":15,"children":1313},[1314],{"text":1275,"type":19},{"type":15,"children":1316},[1317],{"text":1318,"type":19},"  CONSTRAINT fk_projects_owner",{"type":15,"children":1320},[1321],{"text":1322,"type":19},"    FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE CASCADE",{"type":15,"children":1324},[1325],{"text":1238,"type":19},{"type":15,"children":1327},[1328],{"text":23,"type":19},{"type":15,"children":1330},[1331],{"text":1332,"type":19},"CREATE TABLE project_members (",{"type":15,"children":1334},[1335],{"text":1222,"type":19},{"type":15,"children":1337},[1338],{"text":1339,"type":19},"  project_id UUID NOT NULL,",{"type":15,"children":1341},[1342],{"text":1343,"type":19},"  user_id UUID NOT NULL,",{"type":15,"children":1345},[1346],{"text":1347,"type":19},"  joined_at TIMESTAMP NOT NULL DEFAULT NOW(),",{"type":15,"children":1349},[1350],{"text":1351,"type":19},"  CONSTRAINT fk_project_members_project",{"type":15,"children":1353},[1354],{"text":1355,"type":19},"    FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,",{"type":15,"children":1357},[1358],{"text":1359,"type":19},"  CONSTRAINT fk_project_members_user",{"type":15,"children":1361},[1362],{"text":1363,"type":19},"    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,",{"type":15,"children":1365},[1366],{"text":1367,"type":19},"  CONSTRAINT uq_project_member UNIQUE (project_id, user_id)",{"type":15,"children":1369},[1370],{"text":1238,"type":19},{"type":15,"children":1372},[1373],{"text":23,"type":19},{"type":15,"children":1375},[1376],{"text":1377,"type":19},"CREATE TABLE tasks (",{"type":15,"children":1379},[1380],{"text":1222,"type":19},{"type":15,"children":1382},[1383],{"text":1384,"type":19},"  title VARCHAR(150) NOT NULL,",{"type":15,"children":1386},[1387],{"text":1304,"type":19},{"type":15,"children":1389},[1390],{"text":1391,"type":19},"  status VARCHAR(20) NOT NULL DEFAULT 'todo',",{"type":15,"children":1393},[1394],{"text":1395,"type":19},"  priority VARCHAR(20) NOT NULL DEFAULT 'medium',",{"type":15,"children":1397},[1398],{"text":1339,"type":19},{"type":15,"children":1400},[1401],{"text":1402,"type":19},"  assignee_id UUID,",{"type":15,"children":1404},[1405],{"text":1406,"type":19},"  created_by UUID NOT NULL,",{"type":15,"children":1408},[1409],{"text":1410,"type":19},"  due_date TIMESTAMP,",{"type":15,"children":1412},[1413],{"text":1230,"type":19},{"type":15,"children":1415},[1416],{"text":1275,"type":19},{"type":15,"children":1418},[1419],{"text":1420,"type":19},"  CONSTRAINT fk_tasks_project",{"type":15,"children":1422},[1423],{"text":1355,"type":19},{"type":15,"children":1425},[1426],{"text":1427,"type":19},"  CONSTRAINT fk_tasks_assignee",{"type":15,"children":1429},[1430],{"text":1431,"type":19},"    FOREIGN KEY (assignee_id) REFERENCES users(id) ON DELETE SET NULL,",{"type":15,"children":1433},[1434],{"text":1435,"type":19},"  CONSTRAINT fk_tasks_created_by",{"type":15,"children":1437},[1438],{"text":1439,"type":19},"    FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT,",{"type":15,"children":1441},[1442],{"text":1443,"type":19},"  CONSTRAINT chk_tasks_status",{"type":15,"children":1445},[1446],{"text":1447,"type":19},"    CHECK (status IN ('todo', 'in_progress', 'done')),",{"type":15,"children":1449},[1450],{"text":1451,"type":19},"  CONSTRAINT chk_tasks_priority",{"type":15,"children":1453},[1454],{"text":1455,"type":19},"    CHECK (priority IN ('low', 'medium', 'high'))",{"type":15,"children":1457},[1458],{"text":1238,"type":19},{"type":15,"children":1460},[1461],{"text":23,"type":19},{"type":15,"children":1463},[1464],{"text":1465,"type":19},"CREATE TABLE comments (",{"type":15,"children":1467},[1468],{"text":1222,"type":19},{"type":15,"children":1470},[1471],{"text":1472,"type":19},"  task_id UUID NOT NULL,",{"type":15,"children":1474},[1475],{"text":1476,"type":19},"  author_id UUID NOT NULL,",{"type":15,"children":1478},[1479],{"text":1480,"type":19},"  content TEXT NOT NULL,",{"type":15,"children":1482},[1483],{"text":1230,"type":19},{"type":15,"children":1485},[1486],{"text":1275,"type":19},{"type":15,"children":1488},[1489],{"text":1490,"type":19},"  CONSTRAINT fk_comments_task",{"type":15,"children":1492},[1493],{"text":1494,"type":19},"    FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,",{"type":15,"children":1496},[1497],{"text":1498,"type":19},"  CONSTRAINT fk_comments_author",{"type":15,"children":1500},[1501],{"text":1502,"type":19},"    FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE",{"type":15,"children":1504},[1505],{"text":1238,"type":19},{"type":15,"children":1507},[1508],{"text":317,"type":19},{"type":15,"children":1510},[1511],{"text":23,"type":19},{"type":15,"children":1513},[1514],{"text":1515,"type":19},"Supabase includes a SQL editor and table editor for working directly with Postgres, which makes it a good platform for teaching both visual and SQL-first database workflows. ([Supabase][9])",{"type":15,"children":1517},[1518],{"text":23,"type":19},{"type":15,"children":1520},[1521],{"text":1522,"type":19},"### 13. Step 10 — Configure Prisma seeding",{"type":15,"children":1524},[1525],{"text":1526,"type":19},"Prisma documents explicit seeding through `prisma db seed`, using a configured seed command. Its current docs describe seeding as an explicit workflow. ([Prisma][8])",{"type":15,"children":1528},[1529],{"text":23,"type":19},{"type":15,"children":1531},[1532],{"text":1533,"type":19},"#### 13.1 Add seed command",{"type":15,"children":1535},[1536],{"text":1537,"type":19},"Depending on your Prisma version, the docs now reference `prisma.config.ts`, but the key idea is the same: define the command Prisma should run for seeding. ([Prisma][10])",{"type":15,"children":1539},[1540],{"text":23,"type":19},{"type":15,"children":1542},[1543],{"text":1544,"type":19},"For a beginner-friendly setup, add this to `package.json`:",{"type":15,"children":1546},[1547],{"text":1548,"type":19},"```json",{"type":15,"children":1550},[1551],{"text":1552,"type":19},"{",{"type":15,"children":1554},[1555],{"text":1556,"type":19},"  \"prisma\": {",{"type":15,"children":1558},[1559],{"text":1560,"type":19},"    \"seed\": \"ts-node prisma/seed.ts\"",{"type":15,"children":1562},[1563],{"text":1564,"type":19},"  }",{"type":15,"children":1566},[1567],{"text":773,"type":19},{"type":15,"children":1569},[1570],{"text":317,"type":19},{"type":15,"children":1572},[1573],{"text":23,"type":19},{"type":15,"children":1575},[1576],{"text":1577,"type":19},"#### 13.2 Create `prisma/seed.ts`",{"type":15,"children":1579},[1580],{"text":1581,"type":19},"```ts",{"type":15,"children":1583},[1584],{"text":1585,"type":19},"import { PrismaClient } from '@prisma/client'",{"type":15,"children":1587},[1588],{"text":1589,"type":19},"import * as bcrypt from 'bcrypt'",{"type":15,"children":1591},[1592],{"text":23,"type":19},{"type":15,"children":1594},[1595],{"text":1596,"type":19},"const prisma = new PrismaClient()",{"type":15,"children":1598},[1599],{"text":23,"type":19},{"type":15,"children":1601},[1602],{"text":1603,"type":19},"async function main() {",{"type":15,"children":1605},[1606],{"text":1607,"type":19},"  const adminRole = await prisma.role.upsert({",{"type":15,"children":1609},[1610],{"text":1611,"type":19},"    where: { name: 'admin' },",{"type":15,"children":1613},[1614],{"text":1615,"type":19},"    update: {},",{"type":15,"children":1617},[1618],{"text":1619,"type":19},"    create: { name: 'admin' },",{"type":15,"children":1621},[1622],{"text":1623,"type":19},"  })",{"type":15,"children":1625},[1626],{"text":23,"type":19},{"type":15,"children":1628},[1629],{"text":1630,"type":19},"  const memberRole = await prisma.role.upsert({",{"type":15,"children":1632},[1633],{"text":1634,"type":19},"    where: { name: 'member' },",{"type":15,"children":1636},[1637],{"text":1615,"type":19},{"type":15,"children":1639},[1640],{"text":1641,"type":19},"    create: { name: 'member' },",{"type":15,"children":1643},[1644],{"text":1623,"type":19},{"type":15,"children":1646},[1647],{"text":23,"type":19},{"type":15,"children":1649},[1650],{"text":1651,"type":19},"  const adminPassword = await bcrypt.hash('Admin123*', 10)",{"type":15,"children":1653},[1654],{"text":1655,"type":19},"  const memberPassword = await bcrypt.hash('Member123*', 10)",{"type":15,"children":1657},[1658],{"text":23,"type":19},{"type":15,"children":1660},[1661],{"text":1662,"type":19},"  const admin = await prisma.user.upsert({",{"type":15,"children":1664},[1665],{"text":1666,"type":19},"    where: { email: 'admin@taskboard.dev' },",{"type":15,"children":1668},[1669],{"text":1615,"type":19},{"type":15,"children":1671},[1672],{"text":1673,"type":19},"    create: {",{"type":15,"children":1675},[1676],{"text":1677,"type":19},"      fullName: 'System Admin',",{"type":15,"children":1679},[1680],{"text":1681,"type":19},"      email: 'admin@taskboard.dev',",{"type":15,"children":1683},[1684],{"text":1685,"type":19},"      passwordHash: adminPassword,",{"type":15,"children":1687},[1688],{"text":1689,"type":19},"      roleId: adminRole.id,",{"type":15,"children":1691},[1692],{"text":1693,"type":19},"    },",{"type":15,"children":1695},[1696],{"text":1623,"type":19},{"type":15,"children":1698},[1699],{"text":23,"type":19},{"type":15,"children":1701},[1702],{"text":1703,"type":19},"  const member = await prisma.user.upsert({",{"type":15,"children":1705},[1706],{"text":1707,"type":19},"    where: { email: 'member@taskboard.dev' },",{"type":15,"children":1709},[1710],{"text":1615,"type":19},{"type":15,"children":1712},[1713],{"text":1673,"type":19},{"type":15,"children":1715},[1716],{"text":1717,"type":19},"      fullName: 'John Member',",{"type":15,"children":1719},[1720],{"text":1721,"type":19},"      email: 'member@taskboard.dev',",{"type":15,"children":1723},[1724],{"text":1725,"type":19},"      passwordHash: memberPassword,",{"type":15,"children":1727},[1728],{"text":1729,"type":19},"      roleId: memberRole.id,",{"type":15,"children":1731},[1732],{"text":1693,"type":19},{"type":15,"children":1734},[1735],{"text":1623,"type":19},{"type":15,"children":1737},[1738],{"text":23,"type":19},{"type":15,"children":1740},[1741],{"text":1742,"type":19},"  const project = await prisma.project.create({",{"type":15,"children":1744},[1745],{"text":1746,"type":19},"    data: {",{"type":15,"children":1748},[1749],{"text":1750,"type":19},"      name: 'Starter Project',",{"type":15,"children":1752},[1753],{"text":1754,"type":19},"      description: 'Seeded project for learning',",{"type":15,"children":1756},[1757],{"text":1758,"type":19},"      ownerId: admin.id,",{"type":15,"children":1760},[1761],{"text":1693,"type":19},{"type":15,"children":1763},[1764],{"text":1623,"type":19},{"type":15,"children":1766},[1767],{"text":23,"type":19},{"type":15,"children":1769},[1770],{"text":1771,"type":19},"  await prisma.projectMember.createMany({",{"type":15,"children":1773},[1774],{"text":1775,"type":19},"    data: [",{"type":15,"children":1777},[1778],{"text":1779,"type":19},"      { projectId: project.id, userId: admin.id },",{"type":15,"children":1781},[1782],{"text":1783,"type":19},"      { projectId: project.id, userId: member.id },",{"type":15,"children":1785},[1786],{"text":1787,"type":19},"    ],",{"type":15,"children":1789},[1790],{"text":1791,"type":19},"    skipDuplicates: true,",{"type":15,"children":1793},[1794],{"text":1623,"type":19},{"type":15,"children":1796},[1797],{"text":23,"type":19},{"type":15,"children":1799},[1800],{"text":1801,"type":19},"  const task = await prisma.task.create({",{"type":15,"children":1803},[1804],{"text":1746,"type":19},{"type":15,"children":1806},[1807],{"text":1808,"type":19},"      title: 'Build the auth module',",{"type":15,"children":1810},[1811],{"text":1812,"type":19},"      description: 'Create registration and login endpoints',",{"type":15,"children":1814},[1815],{"text":1816,"type":19},"      status: 'in_progress',",{"type":15,"children":1818},[1819],{"text":1820,"type":19},"      priority: 'high',",{"type":15,"children":1822},[1823],{"text":1824,"type":19},"      projectId: project.id,",{"type":15,"children":1826},[1827],{"text":1828,"type":19},"      assigneeId: member.id,",{"type":15,"children":1830},[1831],{"text":1832,"type":19},"      createdBy: admin.id,",{"type":15,"children":1834},[1835],{"text":1693,"type":19},{"type":15,"children":1837},[1838],{"text":1623,"type":19},{"type":15,"children":1840},[1841],{"text":23,"type":19},{"type":15,"children":1843},[1844],{"text":1845,"type":19},"  await prisma.comment.create({",{"type":15,"children":1847},[1848],{"text":1746,"type":19},{"type":15,"children":1850},[1851],{"text":1852,"type":19},"      taskId: task.id,",{"type":15,"children":1854},[1855],{"text":1856,"type":19},"      authorId: admin.id,",{"type":15,"children":1858},[1859],{"text":1860,"type":19},"      content: 'Start with DTOs and JWT strategy.',",{"type":15,"children":1862},[1863],{"text":1693,"type":19},{"type":15,"children":1865},[1866],{"text":1623,"type":19},{"type":15,"children":1868},[1869],{"text":773,"type":19},{"type":15,"children":1871},[1872],{"text":23,"type":19},{"type":15,"children":1874},[1875],{"text":1876,"type":19},"main()",{"type":15,"children":1878},[1879],{"text":1880,"type":19},"  .then(async () => {",{"type":15,"children":1882},[1883],{"text":1884,"type":19},"    await prisma.$disconnect()",{"type":15,"children":1886},[1887],{"text":1623,"type":19},{"type":15,"children":1889},[1890],{"text":1891,"type":19},"  .catch(async (error) => {",{"type":15,"children":1893},[1894],{"text":1895,"type":19},"    console.error(error)",{"type":15,"children":1897},[1898],{"text":1884,"type":19},{"type":15,"children":1900},[1901],{"text":1902,"type":19},"    process.exit(1)",{"type":15,"children":1904},[1905],{"text":1623,"type":19},{"type":15,"children":1907},[1908],{"text":317,"type":19},{"type":15,"children":1910},[1911],{"text":23,"type":19},{"type":15,"children":1913},[1914],{"text":1915,"type":19},"#### 13.3 Run the seed",{"type":15,"children":1917},[1918],{"text":309,"type":19},{"type":15,"children":1920},[1921],{"text":1922,"type":19},"npx prisma db seed",{"type":15,"children":1924},[1925],{"text":317,"type":19},{"type":15,"children":1927},[1928],{"text":23,"type":19},{"type":15,"children":1930},[1931],{"text":1932,"type":19},"That gives the beginner a working database with real data immediately, which is way better than staring at empty tables like a confused pigeon. Prisma explicitly supports this seed workflow. ([Prisma][8])",{"type":15,"children":1934},[1935],{"text":23,"type":19},{"type":15,"children":1937},[1938],{"text":1939,"type":19},"### 14. Step 11 — Create the project structure in NestJS",{"type":15,"children":1941},[1942],{"text":1943,"type":19},"Use this structure:",{"type":15,"children":1945},[1946],{"text":595,"type":19},{"type":15,"children":1948},[1949],{"text":1950,"type":19},"src/",{"type":15,"children":1952},[1953],{"text":1954,"type":19},"  main.ts",{"type":15,"children":1956},[1957],{"text":1958,"type":19},"  app.module.ts",{"type":15,"children":1960},[1961],{"text":1962,"type":19},"  prisma/",{"type":15,"children":1964},[1965],{"text":1966,"type":19},"    prisma.module.ts",{"type":15,"children":1968},[1969],{"text":1970,"type":19},"    prisma.service.ts",{"type":15,"children":1972},[1973],{"text":1974,"type":19},"  common/",{"type":15,"children":1976},[1977],{"text":1978,"type":19},"    guards/",{"type":15,"children":1980},[1981],{"text":1982,"type":19},"    decorators/",{"type":15,"children":1984},[1985],{"text":1986,"type":19},"    filters/",{"type":15,"children":1988},[1989],{"text":1990,"type":19},"  modules/",{"type":15,"children":1992},[1993],{"text":1994,"type":19},"    auth/",{"type":15,"children":1996},[1997],{"text":1998,"type":19},"      dto/",{"type":15,"children":2000},[2001],{"text":2002,"type":19},"      strategies/",{"type":15,"children":2004},[2005],{"text":2006,"type":19},"      auth.controller.ts",{"type":15,"children":2008},[2009],{"text":2010,"type":19},"      auth.service.ts",{"type":15,"children":2012},[2013],{"text":2014,"type":19},"      auth.module.ts",{"type":15,"children":2016},[2017],{"text":2018,"type":19},"    users/",{"type":15,"children":2020},[2021],{"text":1998,"type":19},{"type":15,"children":2023},[2024],{"text":2025,"type":19},"      users.controller.ts",{"type":15,"children":2027},[2028],{"text":2029,"type":19},"      users.service.ts",{"type":15,"children":2031},[2032],{"text":2033,"type":19},"      users.module.ts",{"type":15,"children":2035},[2036],{"text":2037,"type":19},"    projects/",{"type":15,"children":2039},[2040],{"text":1998,"type":19},{"type":15,"children":2042},[2043],{"text":2044,"type":19},"      projects.controller.ts",{"type":15,"children":2046},[2047],{"text":2048,"type":19},"      projects.service.ts",{"type":15,"children":2050},[2051],{"text":2052,"type":19},"      projects.module.ts",{"type":15,"children":2054},[2055],{"text":2056,"type":19},"    tasks/",{"type":15,"children":2058},[2059],{"text":1998,"type":19},{"type":15,"children":2061},[2062],{"text":2063,"type":19},"      tasks.controller.ts",{"type":15,"children":2065},[2066],{"text":2067,"type":19},"      tasks.service.ts",{"type":15,"children":2069},[2070],{"text":2071,"type":19},"      tasks.module.ts",{"type":15,"children":2073},[2074],{"text":2075,"type":19},"    comments/",{"type":15,"children":2077},[2078],{"text":1998,"type":19},{"type":15,"children":2080},[2081],{"text":2082,"type":19},"      comments.controller.ts",{"type":15,"children":2084},[2085],{"text":2086,"type":19},"      comments.service.ts",{"type":15,"children":2088},[2089],{"text":2090,"type":19},"      comments.module.ts",{"type":15,"children":2092},[2093],{"text":317,"type":19},{"type":15,"children":2095},[2096],{"text":23,"type":19},{"type":15,"children":2098},[2099],{"text":2100,"type":19},"Nest’s CLI and architecture guidance encourage modular organization, and the Prisma recipe fits naturally into a dedicated Prisma service and module. ([NestJS Docs][1])",{"type":15,"children":2102},[2103],{"text":23,"type":19},{"type":15,"children":2105},[2106],{"text":2107,"type":19},"### 15. Step 12 — Create Prisma service in NestJS",{"type":15,"children":2109},[2110],{"text":2111,"type":19},"#### `src/prisma/prisma.service.ts`",{"type":15,"children":2113},[2114],{"text":1581,"type":19},{"type":15,"children":2116},[2117],{"text":2118,"type":19},"import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common'",{"type":15,"children":2120},[2121],{"text":1585,"type":19},{"type":15,"children":2123},[2124],{"text":23,"type":19},{"type":15,"children":2126},[2127],{"text":2128,"type":19},"@Injectable()",{"type":15,"children":2130},[2131],{"text":2132,"type":19},"export class PrismaService extends PrismaClient implements OnModuleInit {",{"type":15,"children":2134},[2135],{"text":2136,"type":19},"  async onModuleInit() {",{"type":15,"children":2138},[2139],{"text":2140,"type":19},"    await this.$connect()",{"type":15,"children":2142},[2143],{"text":1564,"type":19},{"type":15,"children":2145},[2146],{"text":23,"type":19},{"type":15,"children":2148},[2149],{"text":2150,"type":19},"  async enableShutdownHooks(app: INestApplication) {",{"type":15,"children":2152},[2153],{"text":2154,"type":19},"    process.on('beforeExit', async () => {",{"type":15,"children":2156},[2157],{"text":2158,"type":19},"      await app.close()",{"type":15,"children":2160},[2161],{"text":2162,"type":19},"    })",{"type":15,"children":2164},[2165],{"text":1564,"type":19},{"type":15,"children":2167},[2168],{"text":773,"type":19},{"type":15,"children":2170},[2171],{"text":317,"type":19},{"type":15,"children":2173},[2174],{"text":23,"type":19},{"type":15,"children":2176},[2177],{"text":2178,"type":19},"#### `src/prisma/prisma.module.ts`",{"type":15,"children":2180},[2181],{"text":1581,"type":19},{"type":15,"children":2183},[2184],{"text":2185,"type":19},"import { Global, Module } from '@nestjs/common'",{"type":15,"children":2187},[2188],{"text":2189,"type":19},"import { PrismaService } from './prisma.service'",{"type":15,"children":2191},[2192],{"text":23,"type":19},{"type":15,"children":2194},[2195],{"text":2196,"type":19},"@Global()",{"type":15,"children":2198},[2199],{"text":2200,"type":19},"@Module({",{"type":15,"children":2202},[2203],{"text":2204,"type":19},"  providers: [PrismaService],",{"type":15,"children":2206},[2207],{"text":2208,"type":19},"  exports: [PrismaService],",{"type":15,"children":2210},[2211],{"text":2212,"type":19},"})",{"type":15,"children":2214},[2215],{"text":2216,"type":19},"export class PrismaModule {}",{"type":15,"children":2218},[2219],{"text":317,"type":19},{"type":15,"children":2221},[2222],{"text":23,"type":19},{"type":15,"children":2224},[2225],{"text":2226,"type":19},"This pattern follows the official Nest Prisma recipe: Prisma Client is wrapped in a service and injected into the app. ([NestJS Docs][6])",{"type":15,"children":2228},[2229],{"text":23,"type":19},{"type":15,"children":2231},[2232],{"text":2233,"type":19},"### 16. Step 13 — Configure Nest environment support",{"type":15,"children":2235},[2236],{"text":2237,"type":19},"In `app.module.ts`:",{"type":15,"children":2239},[2240],{"text":1581,"type":19},{"type":15,"children":2242},[2243],{"text":2244,"type":19},"import { Module } from '@nestjs/common'",{"type":15,"children":2246},[2247],{"text":2248,"type":19},"import { ConfigModule } from '@nestjs/config'",{"type":15,"children":2250},[2251],{"text":2252,"type":19},"import { PrismaModule } from './prisma/prisma.module'",{"type":15,"children":2254},[2255],{"text":23,"type":19},{"type":15,"children":2257},[2258],{"text":2200,"type":19},{"type":15,"children":2260},[2261],{"text":2262,"type":19},"  imports: [",{"type":15,"children":2264},[2265],{"text":2266,"type":19},"    ConfigModule.forRoot({",{"type":15,"children":2268},[2269],{"text":2270,"type":19},"      isGlobal: true,",{"type":15,"children":2272},[2273],{"text":2274,"type":19},"    }),",{"type":15,"children":2276},[2277],{"text":2278,"type":19},"    PrismaModule,",{"type":15,"children":2280},[2281],{"text":2282,"type":19},"  ],",{"type":15,"children":2284},[2285],{"text":2212,"type":19},{"type":15,"children":2287},[2288],{"text":2289,"type":19},"export class AppModule {}",{"type":15,"children":2291},[2292],{"text":317,"type":19},{"type":15,"children":2294},[2295],{"text":23,"type":19},{"type":15,"children":2297},[2298],{"text":2299,"type":19},"Nest’s configuration docs recommend using `@nestjs/config` for loading and managing environment variables. ([NestJS Docs][6])",{"type":15,"children":2301},[2302],{"text":23,"type":19},{"type":15,"children":2304},[2305],{"text":2306,"type":19},"### 17. Step 14 — Authentication roadmap",{"type":15,"children":2308},[2309],{"text":2310,"type":19},"Now build authentication first. Not later. Not “after everything else.” That is how beginner backends turn into spaghetti with a JWT sticker slapped on top.",{"type":15,"children":2312},[2313],{"text":23,"type":19},{"type":15,"children":2315},[2316],{"text":2317,"type":19},"Create:",{"type":15,"children":2319},[2320],{"text":2321,"type":19},"* `POST /auth/register`",{"type":15,"children":2323},[2324],{"text":2325,"type":19},"* `POST /auth/login`",{"type":15,"children":2327},[2328],{"text":2329,"type":19},"* `GET /auth/profile`",{"type":15,"children":2331},[2332],{"text":23,"type":19},{"type":15,"children":2334},[2335],{"text":2336,"type":19},"Nest has official authentication guidance, and JWT is one of the standard patterns used with Passport in Nest apps. ([NestJS Docs][6])",{"type":15,"children":2338},[2339],{"text":23,"type":19},{"type":15,"children":2341},[2342],{"text":2343,"type":19},"#### DTOs",{"type":15,"children":2345},[2346],{"text":2347,"type":19},"##### `register.dto.ts`",{"type":15,"children":2349},[2350],{"text":1581,"type":19},{"type":15,"children":2352},[2353],{"text":2354,"type":19},"import { IsEmail, IsNotEmpty, MinLength } from 'class-validator'",{"type":15,"children":2356},[2357],{"text":23,"type":19},{"type":15,"children":2359},[2360],{"text":2361,"type":19},"export class RegisterDto {",{"type":15,"children":2363},[2364],{"text":2365,"type":19},"  @IsNotEmpty()",{"type":15,"children":2367},[2368],{"text":2369,"type":19},"  fullName: string",{"type":15,"children":2371},[2372],{"text":23,"type":19},{"type":15,"children":2374},[2375],{"text":2376,"type":19},"  @IsEmail()",{"type":15,"children":2378},[2379],{"text":2380,"type":19},"  email: string",{"type":15,"children":2382},[2383],{"text":23,"type":19},{"type":15,"children":2385},[2386],{"text":2387,"type":19},"  @MinLength(8)",{"type":15,"children":2389},[2390],{"text":2391,"type":19},"  password: string",{"type":15,"children":2393},[2394],{"text":773,"type":19},{"type":15,"children":2396},[2397],{"text":317,"type":19},{"type":15,"children":2399},[2400],{"text":23,"type":19},{"type":15,"children":2402},[2403],{"text":2404,"type":19},"### `login.dto.ts`",{"type":15,"children":2406},[2407],{"text":23,"type":19},{"type":15,"children":2409},[2410],{"text":1581,"type":19},{"type":15,"children":2412},[2413],{"text":2414,"type":19},"import { IsEmail, MinLength } from 'class-validator'",{"type":15,"children":2416},[2417],{"text":23,"type":19},{"type":15,"children":2419},[2420],{"text":2421,"type":19},"export class LoginDto {",{"type":15,"children":2423},[2424],{"text":2376,"type":19},{"type":15,"children":2426},[2427],{"text":2380,"type":19},{"type":15,"children":2429},[2430],{"text":23,"type":19},{"type":15,"children":2432},[2433],{"text":2387,"type":19},{"type":15,"children":2435},[2436],{"text":2391,"type":19},{"type":15,"children":2438},[2439],{"text":773,"type":19},{"type":15,"children":2441},[2442],{"text":317,"type":19},{"type":15,"children":2444},[2445],{"text":23,"type":19},{"type":15,"children":2447},[2448],{"text":2449,"type":19},"Validation in Nest is commonly wired through pipes and class-validator/class-transformer. ([NestJS Docs][2])",{"type":15,"children":2451},[2452],{"text":23,"type":19},{"type":15,"children":2454},[2455],{"text":2456,"type":19},"### 18. Step 15 — Business modules roadmap",{"type":15,"children":2458},[2459],{"text":2460,"type":19},"After auth, build these modules in this order:",{"type":15,"children":2462},[2463],{"text":23,"type":19},{"type":15,"children":2465},[2466],{"text":2467,"type":19},"#### Users",{"type":15,"children":2469},[2470],{"text":2471,"type":19},"Endpoints:",{"type":15,"children":2473},[2474],{"text":2475,"type":19},"* `GET /users`",{"type":15,"children":2477},[2478],{"text":2479,"type":19},"* `GET /users/:id`",{"type":15,"children":2481},[2482],{"text":2483,"type":19},"* `PATCH /users/:id`",{"type":15,"children":2485},[2486],{"text":2487,"type":19},"* `PATCH /users/:id/deactivate`",{"type":15,"children":2489},[2490],{"text":23,"type":19},{"type":15,"children":2492},[2493],{"text":2494,"type":19},"#### Projects",{"type":15,"children":2496},[2497],{"text":2471,"type":19},{"type":15,"children":2499},[2500],{"text":2501,"type":19},"* `POST /projects`",{"type":15,"children":2503},[2504],{"text":2505,"type":19},"* `GET /projects`",{"type":15,"children":2507},[2508],{"text":2509,"type":19},"* `GET /projects/:id`",{"type":15,"children":2511},[2512],{"text":2513,"type":19},"* `POST /projects/:id/members`",{"type":15,"children":2515},[2516],{"text":2517,"type":19},"* `DELETE /projects/:id/members/:userId`",{"type":15,"children":2519},[2520],{"text":23,"type":19},{"type":15,"children":2522},[2523],{"text":2524,"type":19},"#### Tasks",{"type":15,"children":2526},[2527],{"text":2471,"type":19},{"type":15,"children":2529},[2530],{"text":2531,"type":19},"* `POST /tasks`",{"type":15,"children":2533},[2534],{"text":2535,"type":19},"* `GET /tasks`",{"type":15,"children":2537},[2538],{"text":2539,"type":19},"* `GET /tasks/:id`",{"type":15,"children":2541},[2542],{"text":2543,"type":19},"* `PATCH /tasks/:id`",{"type":15,"children":2545},[2546],{"text":2547,"type":19},"* `PATCH /tasks/:id/status`",{"type":15,"children":2549},[2550],{"text":2551,"type":19},"* `DELETE /tasks/:id`",{"type":15,"children":2553},[2554],{"text":23,"type":19},{"type":15,"children":2556},[2557],{"text":2558,"type":19},"#### Comments",{"type":15,"children":2560},[2561],{"text":2471,"type":19},{"type":15,"children":2563},[2564],{"text":2565,"type":19},"* `POST /comments`",{"type":15,"children":2567},[2568],{"text":2569,"type":19},"* `GET /tasks/:taskId/comments`",{"type":15,"children":2571},[2572],{"text":2573,"type":19},"* `DELETE /comments/:id`",{"type":15,"children":2575},[2576],{"text":23,"type":19},{"type":15,"children":2578},[2579],{"text":2580,"type":19},"Nest’s modular structure and boilerplate generation are designed exactly for this style of feature-by-feature development. ([NestJS Docs][11])",{"type":15,"children":2582},[2583],{"text":23,"type":19},{"type":15,"children":2585},[2586],{"text":2587,"type":19},"### 19. Step 16 — Add global validation",{"type":15,"children":2589},[2590],{"text":2591,"type":19},"In `src/main.ts`:",{"type":15,"children":2593},[2594],{"text":1581,"type":19},{"type":15,"children":2596},[2597],{"text":2598,"type":19},"import { ValidationPipe } from '@nestjs/common'",{"type":15,"children":2600},[2601],{"text":2602,"type":19},"import { NestFactory } from '@nestjs/core'",{"type":15,"children":2604},[2605],{"text":2606,"type":19},"import { AppModule } from './app.module'",{"type":15,"children":2608},[2609],{"text":23,"type":19},{"type":15,"children":2611},[2612],{"text":2613,"type":19},"async function bootstrap() {",{"type":15,"children":2615},[2616],{"text":2617,"type":19},"  const app = await NestFactory.create(AppModule)",{"type":15,"children":2619},[2620],{"text":23,"type":19},{"type":15,"children":2622},[2623],{"text":2624,"type":19},"  app.useGlobalPipes(",{"type":15,"children":2626},[2627],{"text":2628,"type":19},"    new ValidationPipe({",{"type":15,"children":2630},[2631],{"text":2632,"type":19},"      whitelist: true,",{"type":15,"children":2634},[2635],{"text":2636,"type":19},"      forbidNonWhitelisted: true,",{"type":15,"children":2638},[2639],{"text":2640,"type":19},"      transform: true,",{"type":15,"children":2642},[2643],{"text":2274,"type":19},{"type":15,"children":2645},[2646],{"text":2647,"type":19},"  )",{"type":15,"children":2649},[2650],{"text":23,"type":19},{"type":15,"children":2652},[2653],{"text":2654,"type":19},"  await app.listen(process.env.PORT || 3000)",{"type":15,"children":2656},[2657],{"text":773,"type":19},{"type":15,"children":2659},[2660],{"text":2661,"type":19},"bootstrap()",{"type":15,"children":2663},[2664],{"text":317,"type":19},{"type":15,"children":2666},[2667],{"text":23,"type":19},{"type":15,"children":2669},[2670],{"text":2671,"type":19},"This is the standard Nest approach for request validation and input sanitization at the DTO level. ([NestJS Docs][2])",{"type":15,"children":2673},[2674],{"text":23,"type":19},{"type":15,"children":2676},[2677],{"text":2678,"type":19},"### 20. Step 17 — Add Swagger documentation",{"type":15,"children":2680},[2681],{"text":2682,"type":19},"Install Swagger support if not already installed:",{"type":15,"children":2684},[2685],{"text":309,"type":19},{"type":15,"children":2687},[2688],{"text":647,"type":19},{"type":15,"children":2690},[2691],{"text":317,"type":19},{"type":15,"children":2693},[2694],{"text":23,"type":19},{"type":15,"children":2696},[2697],{"text":2698,"type":19},"Then configure it in `main.ts`:",{"type":15,"children":2700},[2701],{"text":23,"type":19},{"type":15,"children":2703},[2704],{"text":1581,"type":19},{"type":15,"children":2706},[2707],{"text":2708,"type":19},"import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'",{"type":15,"children":2710},[2711],{"text":23,"type":19},{"type":15,"children":2713},[2714],{"text":2715,"type":19},"// after app creation",{"type":15,"children":2717},[2718],{"text":2719,"type":19},"const config = new DocumentBuilder()",{"type":15,"children":2721},[2722],{"text":2723,"type":19},"  .setTitle('TaskBoard API')",{"type":15,"children":2725},[2726],{"text":2727,"type":19},"  .setDescription('Backend API built with NestJS, Prisma, and Supabase Postgres')",{"type":15,"children":2729},[2730],{"text":2731,"type":19},"  .setVersion('1.0')",{"type":15,"children":2733},[2734],{"text":2735,"type":19},"  .addBearerAuth()",{"type":15,"children":2737},[2738],{"text":2739,"type":19},"  .build()",{"type":15,"children":2741},[2742],{"text":23,"type":19},{"type":15,"children":2744},[2745],{"text":2746,"type":19},"const document = SwaggerModule.createDocument(app, config)",{"type":15,"children":2748},[2749],{"text":2750,"type":19},"SwaggerModule.setup('docs', app, document)",{"type":15,"children":2752},[2753],{"text":317,"type":19},{"type":15,"children":2755},[2756],{"text":23,"type":19},{"type":15,"children":2758},[2759],{"text":2760,"type":19},"Nest officially documents Swagger integration for API documentation. ([NestJS Docs][2])",{"type":15,"children":2762},[2763],{"text":23,"type":19},{"type":15,"children":2765},[2766],{"text":2767,"type":19},"### 21. Step 18 — Local testing workflow",{"type":15,"children":2769},[2770],{"text":2771,"type":19},"The beginner should test after every major milestone.",{"type":15,"children":2773},[2774],{"text":23,"type":19},{"type":15,"children":2776},[2777],{"text":2778,"type":19},"Test this order:",{"type":15,"children":2780},[2781],{"text":2782,"type":19},"1. app boots",{"type":15,"children":2784},[2785],{"text":2786,"type":19},"2. Prisma connects",{"type":15,"children":2788},[2789],{"text":2790,"type":19},"3. migration succeeds",{"type":15,"children":2792},[2793],{"text":2794,"type":19},"4. seed succeeds",{"type":15,"children":2796},[2797],{"text":2798,"type":19},"5. register works",{"type":15,"children":2800},[2801],{"text":2802,"type":19},"6. login works",{"type":15,"children":2804},[2805],{"text":2806,"type":19},"7. token protects private routes",{"type":15,"children":2808},[2809],{"text":2810,"type":19},"8. project creation works",{"type":15,"children":2812},[2813],{"text":2814,"type":19},"9. task creation works",{"type":15,"children":2816},[2817],{"text":2818,"type":19},"10. comment creation works",{"type":15,"children":2820},[2821],{"text":23,"type":19},{"type":15,"children":2823},[2824],{"text":2825,"type":19},"Nest creates tests and scripts as part of the generated project structure, which supports this incremental workflow. ([NestJS Docs][7])",{"type":15,"children":2827},[2828],{"text":23,"type":19},{"type":15,"children":2830},[2831],{"text":2832,"type":19},"### 22. Step 19 — Suggested week-by-week plan",{"type":15,"children":2834},[2835],{"text":23,"type":19},{"type":15,"children":2837},[2838],{"text":2839,"type":19},"#### Week 1",{"type":15,"children":2841},[2842],{"text":2843,"type":19},"* install tools",{"type":15,"children":2845},[2846],{"text":2847,"type":19},"* create Supabase project",{"type":15,"children":2849},[2850],{"text":2851,"type":19},"* create Nest app",{"type":15,"children":2853},[2854],{"text":2855,"type":19},"* install dependencies",{"type":15,"children":2857},[2858],{"text":2859,"type":19},"* initialize Prisma",{"type":15,"children":2861},[2862],{"text":2863,"type":19},"* configure `.env`",{"type":15,"children":2865},[2866],{"text":23,"type":19},{"type":15,"children":2868},[2869],{"text":2870,"type":19},"#### Week 2",{"type":15,"children":2872},[2873],{"text":2874,"type":19},"* design the schema",{"type":15,"children":2876},[2877],{"text":2878,"type":19},"* run migration",{"type":15,"children":2880},[2881],{"text":2882,"type":19},"* generate Prisma client",{"type":15,"children":2884},[2885],{"text":2886,"type":19},"* create SQL reference",{"type":15,"children":2888},[2889],{"text":2890,"type":19},"* create seeders",{"type":15,"children":2892},[2893],{"text":2894,"type":19},"* verify seeded data in Supabase Table Editor",{"type":15,"children":2896},[2897],{"text":23,"type":19},{"type":15,"children":2899},[2900],{"text":2901,"type":19},"Supabase’s table tools and SQL editor make it easy to confirm what was created in Postgres. ([Supabase][9])",{"type":15,"children":2903},[2904],{"text":23,"type":19},{"type":15,"children":2906},[2907],{"text":2908,"type":19},"#### Week 3",{"type":15,"children":2910},[2911],{"text":2912,"type":19},"* create Prisma module and service",{"type":15,"children":2914},[2915],{"text":2916,"type":19},"* configure app module",{"type":15,"children":2918},[2919],{"text":2920,"type":19},"* build auth module",{"type":15,"children":2922},[2923],{"text":2924,"type":19},"* add register/login/profile",{"type":15,"children":2926},[2927],{"text":23,"type":19},{"type":15,"children":2929},[2930],{"text":2931,"type":19},"#### Week 4",{"type":15,"children":2933},[2934],{"text":2935,"type":19},"* build users module",{"type":15,"children":2937},[2938],{"text":2939,"type":19},"* build projects module",{"type":15,"children":2941},[2942],{"text":2943,"type":19},"* build tasks module",{"type":15,"children":2945},[2946],{"text":2947,"type":19},"* build comments module",{"type":15,"children":2949},[2950],{"text":23,"type":19},{"type":15,"children":2952},[2953],{"text":2954,"type":19},"#### Week 5",{"type":15,"children":2956},[2957],{"text":2958,"type":19},"* add validation",{"type":15,"children":2960},[2961],{"text":2962,"type":19},"* add route protection",{"type":15,"children":2964},[2965],{"text":2966,"type":19},"* add Swagger",{"type":15,"children":2968},[2969],{"text":2970,"type":19},"* test all endpoints",{"type":15,"children":2972},[2973],{"text":23,"type":19},{"type":15,"children":2975},[2976],{"text":2977,"type":19},"#### Week 6",{"type":15,"children":2979},[2980],{"text":2981,"type":19},"* prepare production env",{"type":15,"children":2983},[2984],{"text":2985,"type":19},"* deploy to Render",{"type":15,"children":2987},[2988],{"text":2989,"type":19},"* connect remote Supabase DB",{"type":15,"children":2991},[2992],{"text":2993,"type":19},"* verify app in production",{"type":15,"children":2995},[2996],{"text":23,"type":19},{"type":15,"children":2998},[2999],{"text":3000,"type":19},"### 23. Step 20 — Deployment to Render",{"type":15,"children":3002},[3003],{"text":3004,"type":19},"Render provides web service deployment documentation and supports connecting a repository, building it, and running a start command. ([NestJS Docs][12])",{"type":15,"children":3006},[3007],{"text":23,"type":19},{"type":15,"children":3009},[3010],{"text":3011,"type":19},"#### 23.1 Push your code to GitHub",{"type":15,"children":3013},[3014],{"text":3015,"type":19},"Create a repository and push the project.",{"type":15,"children":3017},[3018],{"text":23,"type":19},{"type":15,"children":3020},[3021],{"text":3022,"type":19},"#### 23.2 Create a new Web Service in Render",{"type":15,"children":3024},[3025],{"text":3026,"type":19},"Connect the GitHub repository.",{"type":15,"children":3028},[3029],{"text":23,"type":19},{"type":15,"children":3031},[3032],{"text":3033,"type":19},"#### 23.3 Configure build and start commands",{"type":15,"children":3035},[3036],{"text":3037,"type":19},"Build command:",{"type":15,"children":3039},[3040],{"text":309,"type":19},{"type":15,"children":3042},[3043],{"text":3044,"type":19},"npm install && npm run build",{"type":15,"children":3046},[3047],{"text":317,"type":19},{"type":15,"children":3049},[3050],{"text":23,"type":19},{"type":15,"children":3052},[3053],{"text":3054,"type":19},"Start command:",{"type":15,"children":3056},[3057],{"text":309,"type":19},{"type":15,"children":3059},[3060],{"text":3061,"type":19},"node dist/main",{"type":15,"children":3063},[3064],{"text":317,"type":19},{"type":15,"children":3066},[3067],{"text":23,"type":19},{"type":15,"children":3069},[3070],{"text":3071,"type":19},"These match Nest’s standard build and run scripts. ([NestJS Docs][12])",{"type":15,"children":3073},[3074],{"text":23,"type":19},{"type":15,"children":3076},[3077],{"text":3078,"type":19},"#### 23.4 Add environment variables in Render",{"type":15,"children":3080},[3081],{"text":3082,"type":19},"Add:",{"type":15,"children":3084},[3085],{"text":3086,"type":19},"* `PORT`",{"type":15,"children":3088},[3089],{"text":3090,"type":19},"* `DATABASE_URL`",{"type":15,"children":3092},[3093],{"text":3094,"type":19},"* `JWT_SECRET`",{"type":15,"children":3096},[3097],{"text":3098,"type":19},"* `JWT_EXPIRES_IN`",{"type":15,"children":3100},[3101],{"text":23,"type":19},{"type":15,"children":3103},[3104],{"text":3105,"type":19},"#### 23.5 Production database",{"type":15,"children":3107},[3108],{"text":3109,"type":19},"Use the Supabase project’s Postgres connection string as `DATABASE_URL`.",{"type":15,"children":3111},[3112],{"text":23,"type":19},{"type":15,"children":3114},[3115],{"text":3116,"type":19},"#### 23.6 Run production migrations",{"type":15,"children":3118},[3119],{"text":3120,"type":19},"You must apply migrations against production as part of your deployment workflow. Prisma separates development and production migration workflows and documents that clearly. ([Prisma][8])",{"type":15,"children":3122},[3123],{"text":23,"type":19},{"type":15,"children":3125},[3126],{"text":3127,"type":19},"### 24. Step 21 — What the beginner should learn from Supabase specifically",{"type":15,"children":3129},[3130],{"text":3131,"type":19},"This roadmap should explicitly teach these Supabase ideas:",{"type":15,"children":3133},[3134],{"text":3135,"type":19},"* how to create a project",{"type":15,"children":3137},[3138],{"text":3139,"type":19},"* where to find the Postgres connection string",{"type":15,"children":3141},[3142],{"text":3143,"type":19},"* how to open the SQL Editor",{"type":15,"children":3145},[3146],{"text":3147,"type":19},"* how to inspect tables in Table Editor",{"type":15,"children":3149},[3150],{"text":3151,"type":19},"* that Supabase is not “just auth”; it includes Postgres as the core",{"type":15,"children":3153},[3154],{"text":3155,"type":19},"* that Prisma can use Supabase Postgres as a regular PostgreSQL database",{"type":15,"children":3157},[3158],{"text":23,"type":19},{"type":15,"children":3160},[3161],{"text":3162,"type":19},"Supabase’s docs present the platform around a full Postgres database with dashboard tools like the table and SQL editors. ([Supabase][9])",{"type":15,"children":3164},[3165],{"text":23,"type":19},{"type":15,"children":3167},[3168],{"text":3169,"type":19},"### 25. Step 22 — Common mistakes section",{"type":15,"children":3171},[3172],{"text":3173,"type":19},"A beginner roadmap should include this, because pain is a great teacher but a terrible project manager.",{"type":15,"children":3175},[3176],{"text":23,"type":19},{"type":15,"children":3178},[3179],{"text":3180,"type":19},"#### Common mistakes",{"type":15,"children":3182},[3183],{"text":3184,"type":19},"* forgetting to save the Supabase database password",{"type":15,"children":3186},[3187],{"text":3188,"type":19},"* using the wrong `DATABASE_URL`",{"type":15,"children":3190},[3191],{"text":3192,"type":19},"* running Prisma commands before setting `.env`",{"type":15,"children":3194},[3195],{"text":3196,"type":19},"* building endpoints before designing the schema",{"type":15,"children":3198},[3199],{"text":3200,"type":19},"* storing plain text passwords",{"type":15,"children":3202},[3203],{"text":3204,"type":19},"* skipping validation",{"type":15,"children":3206},[3207],{"text":3208,"type":19},"* not protecting private routes",{"type":15,"children":3210},[3211],{"text":3212,"type":19},"* changing the Prisma schema without running migrations",{"type":15,"children":3214},[3215],{"text":3216,"type":19},"* deploying without production environment variables",{"type":15,"children":3218},[3219],{"text":23,"type":19},{"type":15,"children":3221},[3222],{"text":3223,"type":19},"Prisma and Nest both depend heavily on correctly ordered setup steps. If those are skipped, the rest falls apart fast. ([NestJS Docs][1])",{"type":15,"children":3225},[3226],{"text":23,"type":19},{"type":15,"children":3228},[3229],{"text":3230,"type":19},"### 26. Step 23 — Stretch goals after the roadmap",{"type":15,"children":3232},[3233],{"text":3234,"type":19},"After the beginner finishes this version, the next upgrades should be:",{"type":15,"children":3236},[3237],{"text":3238,"type":19},"* refresh tokens",{"type":15,"children":3240},[3241],{"text":3242,"type":19},"* role-based guards",{"type":15,"children":3244},[3245],{"text":3246,"type":19},"* pagination and filtering",{"type":15,"children":3248},[3249],{"text":3250,"type":19},"* soft delete",{"type":15,"children":3252},[3253],{"text":3254,"type":19},"* email verification",{"type":15,"children":3256},[3257],{"text":3258,"type":19},"* file uploads",{"type":15,"children":3260},[3261],{"text":3262,"type":19},"* audit logs",{"type":15,"children":3264},[3265],{"text":3266,"type":19},"* health checks",{"type":15,"children":3268},[3269],{"text":3270,"type":19},"* rate limiting",{"type":15,"children":3272},[3273],{"text":3274,"type":19},"* CI/CD pipeline",{"type":15,"children":3276},[3277],{"text":23,"type":19},{"type":15,"children":3279},[3280],{"text":3281,"type":19},"Nest has official material around health checks and production-oriented patterns, so these are logical next steps after the base API. ([NestJS Docs][13])",{"type":15,"children":3283},[3284],{"text":23,"type":19},{"type":15,"children":3286},[3287],{"text":3288,"type":19},"### 27. Final project deliverables",{"type":15,"children":3290},[3291],{"text":3292,"type":19},"By the end, the student should have:",{"type":15,"children":3294},[3295],{"text":3296,"type":19},"* a Supabase Postgres project",{"type":15,"children":3298},[3299],{"text":3300,"type":19},"* a working NestJS backend",{"type":15,"children":3302},[3303],{"text":3304,"type":19},"* Prisma models",{"type":15,"children":3306},[3307],{"text":3308,"type":19},"* migrations",{"type":15,"children":3310},[3311],{"text":3312,"type":19},"* raw SQL reference",{"type":15,"children":3314},[3315],{"text":3316,"type":19},"* seeders",{"type":15,"children":3318},[3319],{"text":3320,"type":19},"* JWT authentication",{"type":15,"children":3322},[3323],{"text":3324,"type":19},"* business modules",{"type":15,"children":3326},[3327],{"text":3328,"type":19},"* validation",{"type":15,"children":3330},[3331],{"text":3332,"type":19},"* Swagger docs",{"type":15,"children":3334},[3335],{"text":3336,"type":19},"* deployed API on Render",{"type":15,"children":3338},[3339],{"text":23,"type":19},{"type":15,"children":3341},[3342],{"text":3343,"type":19},"That is not a toy. That is a proper first backend journey.",{"type":15,"children":3345},[3346],{"text":23,"type":19},{"type":15,"children":3348},[3349],{"text":3350,"type":19},"[1]: https://docs.nestjs.com/cli/overview \"Overview - CLI | NestJS - A progressive Node.js framework\"",{"type":15,"children":3352},[3353],{"text":3354,"type":19},"[2]: https://docs.nestjs.com/first-steps \"First steps | NestJS - A progressive Node.js framework\"",{"type":15,"children":3356},[3357],{"text":3358,"type":19},"[3]: https://docs.nestjs.com/ \"Documentation | NestJS - A progressive Node.js framework\"",{"type":15,"children":3360},[3361],{"text":3362,"type":19},"[4]: https://supabase.com \"Supabase | The Postgres Development Platform.\"",{"type":15,"children":3364},[3365],{"text":3366,"type":19},"[5]: https://supabase.com/docs/guides/getting-started \"Getting Started | Supabase Docs\"",{"type":15,"children":3368},[3369],{"text":3370,"type":19},"[6]: https://docs.nestjs.com/recipes/prisma \"Prisma | NestJS - A progressive Node.js framework\"",{"type":15,"children":3372},[3373],{"text":3374,"type":19},"[7]: https://docs.nestjs.com/cli/usages \"Usage - CLI | NestJS - A progressive Node.js framework\"",{"type":15,"children":3376},[3377],{"text":3378,"type":19},"[8]: https://www.prisma.io/docs/orm/prisma-migrate/workflows/seeding \"Seeding | Prisma Documentation\"",{"type":15,"children":3380},[3381],{"text":3382,"type":19},"[9]: https://supabase.com/docs/guides/database/overview \"Database | Supabase Docs\"",{"type":15,"children":3384},[3385],{"text":3386,"type":19},"[10]: https://www.prisma.io/docs/orm/reference/prisma-config-reference \"Reference documentation for the prisma config file\"",{"type":15,"children":3388},[3389],{"text":3390,"type":19},"[11]: https://docs.nestjs.com/recipes/crud-generator \"CRUD generator | NestJS - A progressive Node.js framework\"",{"type":15,"children":3392},[3393],{"text":3394,"type":19},"[12]: https://docs.nestjs.com/cli/scripts \"Scripts - CLI | NestJS - A progressive Node.js framework\"",{"type":15,"children":3396},[3397],{"text":3398,"type":19},"[13]: https://docs.nestjs.com/recipes/terminus\"Health checks (Terminus) | NestJS - A progressive Node.js ...\"",{"type":15,"children":3400},[3401],{"text":3402,"type":19},"[14]: https://supabase.com/docs \"Supabase Docs\"","2026-03-21T02:53:32.185Z","2026-03-21T03:06:28.604Z","2026-03-21T03:06:28.754Z",{"id":3407,"documentId":3408,"name":3409,"alternativeText":3410,"caption":3410,"focalPoint":3410,"width":3411,"height":3412,"formats":3413,"hash":3447,"ext":3415,"mime":3418,"size":3448,"url":3449,"previewUrl":3410,"provider":3450,"provider_metadata":3410,"createdAt":3451,"updatedAt":3451,"publishedAt":3452},17,"kdw0vfdv2i3bx74bosi8tvfm","build-beginner-backend-nestjs-prisma-supabase-postgres.png",null,1536,1024,{"large":3414,"small":3424,"medium":3432,"thumbnail":3439},{"ext":3415,"url":3416,"hash":3417,"mime":3418,"name":3419,"path":3410,"size":3420,"width":3421,"height":3422,"sizeInBytes":3423},".png","https://awesome-friends-6b6e40fa18.media.strapiapp.com/large_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d.png","large_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d","image/png","large_build-beginner-backend-nestjs-prisma-supabase-postgres.png",1291.25,1000,667,1291252,{"ext":3415,"url":3425,"hash":3426,"mime":3418,"name":3427,"path":3410,"size":3428,"width":3429,"height":3430,"sizeInBytes":3431},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/small_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d.png","small_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d","small_build-beginner-backend-nestjs-prisma-supabase-postgres.png",345.61,500,333,345611,{"ext":3415,"url":3433,"hash":3434,"mime":3418,"name":3435,"path":3410,"size":3436,"width":3437,"height":3429,"sizeInBytes":3438},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/medium_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d.png","medium_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d","medium_build-beginner-backend-nestjs-prisma-supabase-postgres.png",745.02,750,745015,{"ext":3415,"url":3440,"hash":3441,"mime":3418,"name":3442,"path":3410,"size":3443,"width":3444,"height":3445,"sizeInBytes":3446},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/thumbnail_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d.png","thumbnail_build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d","thumbnail_build-beginner-backend-nestjs-prisma-supabase-postgres.png",85.18,234,156,85179,"build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d",663.37,"https://awesome-friends-6b6e40fa18.media.strapiapp.com/build_beginner_backend_nestjs_prisma_supabase_postgres_d4a1fe998d.png","strapi-provider-upload-strapi-cloud","2026-03-21T03:05:16.193Z","2026-03-21T03:05:16.194Z",{"id":3454,"documentId":3455,"name":3456,"slug":3457,"bio":3458,"createdAt":3459,"updatedAt":3459,"publishedAt":3460},1,"v47xc4w0scmvr4q884stes9o","Jose Henriquez","author","Desarrollador de software y estudiante de Ingeniería en Sistemas, apasionado por la tecnología, la creación de soluciones digitales y la construcción de proyectos con impacto real. Se caracteriza por ser una persona autodidacta, creativa y enfocada en convertir ideas en resultados concretos.","2026-03-08T18:07:58.711Z","2026-03-08T18:07:58.660Z",[3462,3509,3555],{"id":3463,"documentId":3464,"title":3465,"slug":3466,"excerpt":3467,"difficulty":3468,"estimatedCost":3469,"seoTitle":3470,"seoDescription":3471,"createdAt":3472,"updatedAt":3473,"publishedAt":3474,"maturity":3475,"coverImage":3476},18,"ry8zfojo2yql8s554das8x27","Scalable NestJS Backend Stack","scalable-nest-js-backend-stack","A structured backend stack for teams that want strong TypeScript support, scalable architecture, reliable relational data, and clean long-term maintainability for modern APIs and backend systems.","intermediate","Low to moderate, depending on scale","Scalable NestJS Backend Stack Guide","Learn when to use NestJS with PostgreSQL, Prisma, Redis, and BullMQ for scalable APIs, SaaS platforms, queue-driven systems, and modern TypeScript backend services.","2026-03-11T02:07:18.303Z","2026-03-11T02:10:19.671Z","2026-03-11T02:10:19.872Z","stable",{"id":3477,"documentId":3478,"name":3479,"alternativeText":3410,"caption":3410,"focalPoint":3410,"width":3411,"height":3412,"formats":3480,"hash":3505,"ext":3415,"mime":3418,"size":3506,"url":3507,"previewUrl":3410,"provider":3450,"provider_metadata":3410,"createdAt":3508,"updatedAt":3508,"publishedAt":3508},8,"iiixq48ujzm6kfz3si5qbk9x","Scalable NestJS Backend Stack.png",{"large":3481,"small":3487,"medium":3493,"thumbnail":3499},{"ext":3415,"url":3482,"hash":3483,"mime":3418,"name":3484,"path":3410,"size":3485,"width":3421,"height":3422,"sizeInBytes":3486},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/large_Scalable_Nest_JS_Backend_Stack_c52c6aa299.png","large_Scalable_Nest_JS_Backend_Stack_c52c6aa299","large_Scalable NestJS Backend Stack.png",1280.39,1280388,{"ext":3415,"url":3488,"hash":3489,"mime":3418,"name":3490,"path":3410,"size":3491,"width":3429,"height":3430,"sizeInBytes":3492},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/small_Scalable_Nest_JS_Backend_Stack_c52c6aa299.png","small_Scalable_Nest_JS_Backend_Stack_c52c6aa299","small_Scalable NestJS Backend Stack.png",307.8,307801,{"ext":3415,"url":3494,"hash":3495,"mime":3418,"name":3496,"path":3410,"size":3497,"width":3437,"height":3429,"sizeInBytes":3498},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/medium_Scalable_Nest_JS_Backend_Stack_c52c6aa299.png","medium_Scalable_Nest_JS_Backend_Stack_c52c6aa299","medium_Scalable NestJS Backend Stack.png",704.24,704237,{"ext":3415,"url":3500,"hash":3501,"mime":3418,"name":3502,"path":3410,"size":3503,"width":3444,"height":3445,"sizeInBytes":3504},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/thumbnail_Scalable_Nest_JS_Backend_Stack_c52c6aa299.png","thumbnail_Scalable_Nest_JS_Backend_Stack_c52c6aa299","thumbnail_Scalable NestJS Backend Stack.png",71.92,71922,"Scalable_Nest_JS_Backend_Stack_c52c6aa299",935.84,"https://awesome-friends-6b6e40fa18.media.strapiapp.com/Scalable_Nest_JS_Backend_Stack_c52c6aa299.png","2026-03-11T01:48:45.609Z",{"id":3510,"documentId":3511,"title":3512,"slug":3513,"excerpt":3514,"difficulty":11,"estimatedCost":3515,"seoTitle":3516,"seoDescription":3517,"createdAt":3518,"updatedAt":3519,"publishedAt":3520,"maturity":3475,"coverImage":3521},5,"ru06yk2a087zqapworwd6rsg","Nuxt 4 + Strapi 5","nuxt-4-strapi-5-primevue","A modern content-driven stack for SEO-friendly websites, blogs, documentation platforms, and scalable editorial projects.","Low to medium depending on hosting, media usage, and database provider.","Nuxt 4 + Strapi 5 + PrimeVueStack Guide for Modern Content-Driven Websites","Learn when to use Nuxt 4 with Strapi 5 and Prime Vue Components, its strengths, limitations, architecture patterns, and official resources for production-ready projects.","2026-03-08T18:43:39.573Z","2026-03-08T18:57:30.703Z","2026-03-08T18:57:30.958Z",{"id":3522,"documentId":3523,"name":3524,"alternativeText":3410,"caption":3410,"focalPoint":3410,"width":3411,"height":3412,"formats":3525,"hash":3550,"ext":3415,"mime":3418,"size":3551,"url":3552,"previewUrl":3410,"provider":3450,"provider_metadata":3410,"createdAt":3553,"updatedAt":3553,"publishedAt":3554},2,"b46gf1zi57op33uk2w07h9j6","modernwebdashboard.png",{"large":3526,"small":3532,"medium":3538,"thumbnail":3544},{"ext":3415,"url":3527,"hash":3528,"mime":3418,"name":3529,"path":3410,"size":3530,"width":3421,"height":3422,"sizeInBytes":3531},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/large_modernwebdashboard_b49d2560d2.png","large_modernwebdashboard_b49d2560d2","large_modernwebdashboard.png",990.81,990808,{"ext":3415,"url":3533,"hash":3534,"mime":3418,"name":3535,"path":3410,"size":3536,"width":3429,"height":3430,"sizeInBytes":3537},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/small_modernwebdashboard_b49d2560d2.png","small_modernwebdashboard_b49d2560d2","small_modernwebdashboard.png",268.68,268682,{"ext":3415,"url":3539,"hash":3540,"mime":3418,"name":3541,"path":3410,"size":3542,"width":3437,"height":3429,"sizeInBytes":3543},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/medium_modernwebdashboard_b49d2560d2.png","medium_modernwebdashboard_b49d2560d2","medium_modernwebdashboard.png",571.02,571018,{"ext":3415,"url":3545,"hash":3546,"mime":3418,"name":3547,"path":3410,"size":3548,"width":3444,"height":3445,"sizeInBytes":3549},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/thumbnail_modernwebdashboard_b49d2560d2.png","thumbnail_modernwebdashboard_b49d2560d2","thumbnail_modernwebdashboard.png",69.13,69125,"modernwebdashboard_b49d2560d2",574.58,"https://awesome-friends-6b6e40fa18.media.strapiapp.com/modernwebdashboard_b49d2560d2.png","2026-03-08T18:43:20.691Z","2026-03-08T18:43:20.698Z",{"id":3556,"documentId":3557,"title":3558,"slug":3559,"excerpt":3560,"difficulty":3468,"estimatedCost":3561,"seoTitle":3562,"seoDescription":3563,"createdAt":3564,"updatedAt":3564,"publishedAt":3565,"maturity":3475,"coverImage":3566},4,"zu3qggap5kjtcwsfzkm1a1zf","Next.js + Sanity","nextjs-sanity","A flexible stack for content-rich websites that need strong editorial tooling, fast previews, and modern React-based frontend delivery.","Medium depending on content volume, image delivery, preview usage, and hosting plan. seoTitle: Next.js + Sanity Stack Guide for Content Platforms and Modern Editorial Sites","Next.js + Sanity Stack Guide for Content Platforms and Modern Editorial Sites","Explore the Next.js + Sanity stack, including architecture, ideal use cases, benefits, trade-offs, and key documentation resources.","2026-03-08T18:51:03.536Z","2026-03-08T18:51:03.784Z",{"id":3567,"documentId":3568,"name":3569,"alternativeText":3410,"caption":3410,"focalPoint":3410,"width":3411,"height":3412,"formats":3570,"hash":3595,"ext":3415,"mime":3418,"size":3596,"url":3597,"previewUrl":3410,"provider":3450,"provider_metadata":3410,"createdAt":3598,"updatedAt":3598,"publishedAt":3599},3,"ml2ee2zpq4kzbtab101u9ghd","sanitynextjs.png",{"large":3571,"small":3577,"medium":3583,"thumbnail":3589},{"ext":3415,"url":3572,"hash":3573,"mime":3418,"name":3574,"path":3410,"size":3575,"width":3421,"height":3422,"sizeInBytes":3576},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/large_sanitynextjs_18c9cce218.png","large_sanitynextjs_18c9cce218","large_sanitynextjs.png",915.04,915039,{"ext":3415,"url":3578,"hash":3579,"mime":3418,"name":3580,"path":3410,"size":3581,"width":3429,"height":3430,"sizeInBytes":3582},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/small_sanitynextjs_18c9cce218.png","small_sanitynextjs_18c9cce218","small_sanitynextjs.png",243.44,243439,{"ext":3415,"url":3584,"hash":3585,"mime":3418,"name":3586,"path":3410,"size":3587,"width":3437,"height":3429,"sizeInBytes":3588},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/medium_sanitynextjs_18c9cce218.png","medium_sanitynextjs_18c9cce218","medium_sanitynextjs.png",524.8,524801,{"ext":3415,"url":3590,"hash":3591,"mime":3418,"name":3592,"path":3410,"size":3593,"width":3444,"height":3445,"sizeInBytes":3594},"https://awesome-friends-6b6e40fa18.media.strapiapp.com/thumbnail_sanitynextjs_18c9cce218.png","thumbnail_sanitynextjs_18c9cce218","thumbnail_sanitynextjs.png",62.39,62392,"sanitynextjs_18c9cce218",521.69,"https://awesome-friends-6b6e40fa18.media.strapiapp.com/sanitynextjs_18c9cce218.png","2026-03-08T18:46:03.464Z","2026-03-08T18:46:03.471Z",{"pagination":3601},{"page":3454,"pageSize":3602,"pageCount":3454,"total":3454},25]