[{"data":1,"prerenderedAt":420},["ShallowReactive",2],{"project-sinvent":3},{"id":4,"title":5,"body":6,"description":401,"duration":402,"extension":403,"featured":404,"github":405,"image":406,"live":407,"meta":408,"navigation":271,"order":281,"path":409,"role":407,"seo":410,"status":411,"stem":412,"team_size":407,"tech":413,"type":417,"year":418,"__hash__":419},"projects\u002Fproject\u002Fsinvent.md","Sinvent - Inventory System",{"type":7,"value":8,"toc":393},"minimark",[9,14,18,22,30,87,91,96,101,127,132,150,154,159,166,304,308,311,389],[10,11,13],"h2",{"id":12},"the-problem","The Problem",[15,16,17],"p",{},"Small to medium enterprises often struggle with disjointed inventory tracking methods—relying on spreadsheets that are prone to human error and lack real-time synchronization. They need a secure, scalable solution to manage products, monitor stock levels, and handle staff access without the complexity of enterprise ERP software.",[10,19,21],{"id":20},"my-solution","My Solution",[15,23,24,25,29],{},"I built ",[26,27,28],"strong",{},"Sinvent",", a robust Full-Stack application designed to bridge the gap between usability and complex data management.",[31,32,33,48,63,77],"ul",{},[34,35,36,39,40,43,44,47],"li",{},[26,37,38],{},"Decoupled Architecture:"," Built with a ",[26,41,42],{},"Laravel 12"," REST API backend and a ",[26,45,46],{},"Vue 3"," Single Page Application (SPA) frontend, allowing for independent scaling and maintenance.",[34,49,50,53,54,57,58,62],{},[26,51,52],{},"Secure Authentication:"," Implemented stateless authentication using ",[26,55,56],{},"JWT (JSON Web Tokens)"," via ",[59,60,61],"code",{},"tymon\u002Fjwt-auth",", ensuring secure and scalable session management across devices.",[34,64,65,68,69,72,73,76],{},[26,66,67],{},"Modern UI\u002FUX:"," Crafted a responsive interface using ",[26,70,71],{},"Tailwind CSS v4"," and ",[26,74,75],{},"Shadcn Vue"," components, prioritizing accessibility and ease of use.",[34,78,79,82,83,86],{},[26,80,81],{},"Data Visualization:"," Integrated ",[26,84,85],{},"Chart.js"," to transform raw inventory data into actionable visual insights for administrators.",[10,88,90],{"id":89},"technical-deep-dive","Technical Deep Dive",[92,93,95],"h3",{"id":94},"architecture-decisions","Architecture Decisions",[15,97,98],{},[26,99,100],{},"Why Laravel 12 over Node.js?",[31,102,103,121],{},[34,104,105,108,109,112,113,116,117,120],{},[26,106,107],{},"Rapid API Development:"," Laravel's Eloquent ORM and API Resource classes allowed me to quickly scaffold complex relationships between ",[59,110,111],{},"Products",", ",[59,114,115],{},"Inventories",", and ",[59,118,119],{},"Members",".",[34,122,123,126],{},[26,124,125],{},"Stability:"," Leveraging Laravel 12's strict typing and built-in security features (like Sanctum\u002FJWT integration) reduced the boilerplate needed for secure endpoints.",[15,128,129],{},[26,130,131],{},"Why Vue 3 & Tailwind v4?",[31,133,134,144],{},[34,135,136,139,140,143],{},[26,137,138],{},"Composition API:"," I utilized Vue 3's Composition API to create reusable logic hooks for data fetching and state management, keeping components like ",[59,141,142],{},"InventoryView.vue"," clean.",[34,145,146,149],{},[26,147,148],{},"Performance:"," Tailwind v4 brings a unified toolchain with faster compilation times, essential for maintaining a swift developer feedback loop.",[92,151,153],{"id":152},"key-features-i-built","Key Features I Built",[155,156,158],"h4",{"id":157},"_1-secure-api-routes-resource-mapping","1. Secure API Routes & Resource Mapping",[15,160,161,162,165],{},"I designed the backend to expose a clean, RESTful API. The routes are protected by a custom ",[59,163,164],{},"auth:api"," middleware group, ensuring that sensitive operations like inventory adjustments are restricted to authenticated users only.",[167,168,173],"pre",{"className":169,"code":170,"language":171,"meta":172,"style":172},"language-bash shiki shiki-themes github-light github-dark","# php\n# be\u002Froutes\u002Fapi.php\nRoute::middleware(\"auth:api\")->group(function () {\n    Route::apiResource(\"\u002Fproducts\", ProductController::class);\n    Route::apiResource(\"\u002Fmembers\", MemberController::class);\n    Route::apiResource(\"\u002Finventories\", InventoryController::class);\n\n    # Custom endpoints for aggregated data\n    Route::get(\"\u002Fproducts\u002Fall\", [ProductController::class, \"all\"]);\n});\n","bash","",[59,174,175,184,190,217,236,251,266,273,279,298],{"__ignoreMap":172},[176,177,180],"span",{"class":178,"line":179},"line",1,[176,181,183],{"class":182},"sJ8bj","# php\n",[176,185,187],{"class":178,"line":186},2,[176,188,189],{"class":182},"# be\u002Froutes\u002Fapi.php\n",[176,191,193,197,200,204,208,211,214],{"class":178,"line":192},3,[176,194,196],{"class":195},"sScJk","Route::middleware(",[176,198,199],{"class":195},"\"auth:api\"",[176,201,203],{"class":202},"sVt8B",")-",[176,205,207],{"class":206},"szBVR",">",[176,209,210],{"class":202},"group(",[176,212,213],{"class":195},"function",[176,215,216],{"class":202}," () {\n",[176,218,220,223,226,229,233],{"class":178,"line":219},4,[176,221,222],{"class":195},"    Route::apiResource(",[176,224,225],{"class":195},"\"\u002Fproducts\"",[176,227,228],{"class":195},",",[176,230,232],{"class":231},"sZZnC"," ProductController::class",[176,234,235],{"class":202},");\n",[176,237,239,241,244,246,249],{"class":178,"line":238},5,[176,240,222],{"class":195},[176,242,243],{"class":195},"\"\u002Fmembers\"",[176,245,228],{"class":195},[176,247,248],{"class":231}," MemberController::class",[176,250,235],{"class":202},[176,252,254,256,259,261,264],{"class":178,"line":253},6,[176,255,222],{"class":195},[176,257,258],{"class":195},"\"\u002Finventories\"",[176,260,228],{"class":195},[176,262,263],{"class":231}," InventoryController::class",[176,265,235],{"class":202},[176,267,269],{"class":178,"line":268},7,[176,270,272],{"emptyLinePlaceholder":271},true,"\n",[176,274,276],{"class":178,"line":275},8,[176,277,278],{"class":182},"    # Custom endpoints for aggregated data\n",[176,280,282,285,288,290,293,296],{"class":178,"line":281},9,[176,283,284],{"class":195},"    Route::get(",[176,286,287],{"class":195},"\"\u002Fproducts\u002Fall\"",[176,289,228],{"class":195},[176,291,292],{"class":202}," [ProductController::class, ",[176,294,295],{"class":231},"\"all\"]",[176,297,235],{"class":202},[176,299,301],{"class":178,"line":300},10,[176,302,303],{"class":202},"});\n",[155,305,307],{"id":306},"_2-reusable-component-library","2. Reusable Component Library",[15,309,310],{},"Instead of hardcoding UI elements, I built a library of atomic components (e.g., BaseTable, BaseCard, BaseAdd) in the frontend. This promotes consistency and drastically reduces code duplication across different views like MemberView and ProductView.",[167,312,314],{"className":169,"code":313,"language":171,"meta":172,"style":172},"# javascript\n# Example structure from fe\u002Fsrc\u002Fcomponents\nimport BaseTable from '@\u002Fcomponents\u002FBaseTable.vue'\nimport BaseCard from '@\u002Fcomponents\u002FBaseCard.vue'\n\n# Used dynamically across views to render data grids\n\u003CBaseTable :data=\"inventoryData\" :columns=\"tableColumns\" \u002F>\n",[59,315,316,321,326,340,352,356,361],{"__ignoreMap":172},[176,317,318],{"class":178,"line":179},[176,319,320],{"class":182},"# javascript\n",[176,322,323],{"class":178,"line":186},[176,324,325],{"class":182},"# Example structure from fe\u002Fsrc\u002Fcomponents\n",[176,327,328,331,334,337],{"class":178,"line":192},[176,329,330],{"class":195},"import",[176,332,333],{"class":231}," BaseTable",[176,335,336],{"class":231}," from",[176,338,339],{"class":231}," '@\u002Fcomponents\u002FBaseTable.vue'\n",[176,341,342,344,347,349],{"class":178,"line":219},[176,343,330],{"class":195},[176,345,346],{"class":231}," BaseCard",[176,348,336],{"class":231},[176,350,351],{"class":231}," '@\u002Fcomponents\u002FBaseCard.vue'\n",[176,353,354],{"class":178,"line":238},[176,355,272],{"emptyLinePlaceholder":271},[176,357,358],{"class":178,"line":253},[176,359,360],{"class":182},"# Used dynamically across views to render data grids\n",[176,362,363,366,369,372,375,378,380,383,386],{"class":178,"line":268},[176,364,365],{"class":206},"\u003C",[176,367,368],{"class":202},"BaseTable :data",[176,370,371],{"class":206},"=",[176,373,374],{"class":231},"\"inventoryData\"",[176,376,377],{"class":195}," :columns",[176,379,371],{"class":231},[176,381,382],{"class":195},"\"tableColumns\"",[176,384,385],{"class":202}," \u002F",[176,387,388],{"class":206},">\n",[390,391,392],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":172,"searchDepth":186,"depth":186,"links":394},[395,396,397],{"id":12,"depth":186,"text":13},{"id":20,"depth":186,"text":21},{"id":89,"depth":186,"text":90,"children":398},[399,400],{"id":94,"depth":192,"text":95},{"id":152,"depth":192,"text":153},"A modern, decoupled inventory management system featuring secure JWT authentication, role-based access control, and interactive data visualization for real-time stock tracking.","5 days","md",false,"https:\u002F\u002Fgithub.com\u002Fszuryuu\u002Fsinvent","\u002Fimages\u002Fprojects\u002Flaravel.png",null,{},"\u002Fproject\u002Fsinvent",{"title":5,"description":401},"Completed","project\u002Fsinvent",[42,46,414,415,416],"MySQL","Tailwind CSS","Shadcn","Solo Project","2025","0QZI8TjOhtT4UurGWlV3mIZAGFJ-kQC8OexJHGyqwpY",1776582962962]