[{"data":1,"prerenderedAt":479},["ShallowReactive",2],{"project-internship-monitoring":3},{"id":4,"title":5,"body":6,"description":460,"duration":461,"extension":462,"featured":463,"github":464,"image":465,"live":466,"meta":467,"navigation":238,"order":248,"path":468,"role":466,"seo":469,"status":470,"stem":471,"team_size":466,"tech":472,"type":476,"year":477,"__hash__":478},"projects\u002Fproject\u002Finternship-monitoring.md","Internship Monitoring",{"type":7,"value":8,"toc":452},"minimark",[9,14,18,22,30,71,75,80,85,120,125,137,141,146,149,347,351,354,448],[10,11,13],"h2",{"id":12},"the-problem","The Problem",[15,16,17],"p",{},"Vocational schools (SMK) and universities face logistical nightmares when managing hundreds of students scattered across different companies for internships (PKL). Tracking attendance, grading, and administrative approval manually via paper logbooks is inefficient and prone to data loss.",[10,19,21],{"id":20},"my-solution","My Solution",[15,23,24,25,29],{},"I developed the ",[26,27,28],"strong",{},"Internship Monitoring System",", a web-based solution that digitizes the entire internship lifecycle.",[31,32,33,44,55,61],"ul",{},[34,35,36,39,40,43],"li",{},[26,37,38],{},"Rapid Admin Development:"," Leveraged ",[26,41,42],{},"Filament PHP"," to build a feature-rich admin panel in record time, allowing teachers to manage Students, Industries, and Internship placements effortlessly.",[34,45,46,49,50,54],{},[26,47,48],{},"API-Ready Architecture:"," Unlike a traditional monolith, I exposed a comprehensive set of RESTful APIs (",[51,52,53],"code",{},"app\u002FHttp\u002FControllers\u002FApi",") to allow future integration with student mobile applications for logbook entry.",[34,56,57,60],{},[26,58,59],{},"Automated State Management:"," Implemented database triggers to handle complex status changes automatically, ensuring data consistency without heavy application-level logic.",[34,62,63,66,67,70],{},[26,64,65],{},"Role-Based Access Control:"," Utilized ",[26,68,69],{},"Filament Shield"," to manage granular permissions between Admins, Teachers, and Staff.",[10,72,74],{"id":73},"technical-deep-dive","Technical Deep Dive",[76,77,79],"h3",{"id":78},"architecture-decisions","Architecture Decisions",[15,81,82],{},[26,83,84],{},"Why Filament PHP?",[31,86,87,98],{},[34,88,89,92,93,97],{},[26,90,91],{},"TALL Stack Efficiency:"," Filament is built on the TALL stack (Tailwind, Alpine, Laravel, Livewire). This allowed me to create reactive, modern UI components for the dashboard (like the ",[94,95,96],"em",{},"Internship Stats Overview"," widget) without writing separate frontend code.",[34,99,100,103,104,107,108,111,112,115,116,119],{},[26,101,102],{},"Resource Management:"," Filament's \"Resource\" pattern (",[51,105,106],{},"app\u002FFilament\u002FAdmin\u002FResources",") drastically reduced boilerplate for CRUD operations on models like ",[51,109,110],{},"BusinessField",", ",[51,113,114],{},"Industry",", and ",[51,117,118],{},"Student",".",[15,121,122],{},[26,123,124],{},"Database-Level Logic (Triggers)",[31,126,127,130],{},[34,128,129],{},"To ensure data integrity regardless of whether data is modified via the API or Admin Panel, I moved critical status logic to the database layer.",[34,131,132,133,136],{},"I wrote a custom migration ",[51,134,135],{},"2025_05_20_143053_internship_triggers"," that installs SQL triggers. These triggers automatically update a student's status (e.g., from 'Active' to 'Interning') whenever a new internship record is created or completed.",[76,138,140],{"id":139},"key-features-i-built","Key Features I Built",[142,143,145],"h4",{"id":144},"_1-hybrid-controller-architecture","1. Hybrid Controller Architecture",[15,147,148],{},"The system serves two masters: the web admin panel and mobile clients. I structured the backend to handle both gracefully.",[150,151,156],"pre",{"className":152,"code":153,"language":154,"meta":155,"style":155},"language-bash shiki shiki-themes github-light github-dark","# php\n# app\u002FHttp\u002FControllers\u002FApi\u002FInternshipController.php\npublic function index(Request $request)\n{\n    # JSON response for Mobile Apps\n    return InternshipResource::collection(Internship::all());\n}\n\n# app\u002FFilament\u002FAdmin\u002FResources\u002FInternshipResource.php\npublic static function form(Form $form): Form\n{\n    # Reactive Form UI for Admin Panel\n    return $form->schema([\n        Select::make('student_id')->relationship('student', 'name'),\n        # ...\n    ]);\n}\n","bash","",[51,157,158,167,173,197,203,209,227,233,240,246,273,278,284,301,330,336,342],{"__ignoreMap":155},[159,160,163],"span",{"class":161,"line":162},"line",1,[159,164,166],{"class":165},"sJ8bj","# php\n",[159,168,170],{"class":161,"line":169},2,[159,171,172],{"class":165},"# app\u002FHttp\u002FControllers\u002FApi\u002FInternshipController.php\n",[159,174,176,180,184,187,191,194],{"class":161,"line":175},3,[159,177,179],{"class":178},"sScJk","public",[159,181,183],{"class":182},"sZZnC"," function",[159,185,186],{"class":182}," index",[159,188,190],{"class":189},"sVt8B","(",[159,192,193],{"class":178},"Request",[159,195,196],{"class":189}," $request)\n",[159,198,200],{"class":161,"line":199},4,[159,201,202],{"class":189},"{\n",[159,204,206],{"class":161,"line":205},5,[159,207,208],{"class":165},"    # JSON response for Mobile Apps\n",[159,210,212,216,219,221,224],{"class":161,"line":211},6,[159,213,215],{"class":214},"szBVR","    return",[159,217,218],{"class":182}," InternshipResource::collection",[159,220,190],{"class":189},[159,222,223],{"class":178},"Internship::all",[159,225,226],{"class":189},"());\n",[159,228,230],{"class":161,"line":229},7,[159,231,232],{"class":189},"}\n",[159,234,236],{"class":161,"line":235},8,[159,237,239],{"emptyLinePlaceholder":238},true,"\n",[159,241,243],{"class":161,"line":242},9,[159,244,245],{"class":165},"# app\u002FFilament\u002FAdmin\u002FResources\u002FInternshipResource.php\n",[159,247,249,251,254,256,259,261,264,267,270],{"class":161,"line":248},10,[159,250,179],{"class":178},[159,252,253],{"class":182}," static",[159,255,183],{"class":182},[159,257,258],{"class":182}," form",[159,260,190],{"class":189},[159,262,263],{"class":178},"Form",[159,265,266],{"class":189}," $form)",[159,268,269],{"class":182},":",[159,271,272],{"class":182}," Form\n",[159,274,276],{"class":161,"line":275},11,[159,277,202],{"class":189},[159,279,281],{"class":161,"line":280},12,[159,282,283],{"class":165},"    # Reactive Form UI for Admin Panel\n",[159,285,287,289,292,295,298],{"class":161,"line":286},13,[159,288,215],{"class":214},[159,290,291],{"class":189}," $form-",[159,293,294],{"class":214},">",[159,296,297],{"class":182},"schema",[159,299,300],{"class":189},"([\n",[159,302,304,307,310,313,315,318,321,324,327],{"class":161,"line":303},14,[159,305,306],{"class":189},"        Select::make(",[159,308,309],{"class":182},"'student_id'",[159,311,312],{"class":189},")-",[159,314,294],{"class":214},[159,316,317],{"class":189},"relationship(",[159,319,320],{"class":182},"'student'",[159,322,323],{"class":214},",",[159,325,326],{"class":182}," 'name'",[159,328,329],{"class":189},"),\n",[159,331,333],{"class":161,"line":332},15,[159,334,335],{"class":165},"        # ...\n",[159,337,339],{"class":161,"line":338},16,[159,340,341],{"class":189},"    ]);\n",[159,343,345],{"class":161,"line":344},17,[159,346,232],{"class":189},[142,348,350],{"id":349},"_2-complex-relationship-management","2. Complex Relationship Management",[15,352,353],{},"The system handles a web of relationships: Students belong to Departments, apply to Industries, and are supervised by Teachers. I modeled this using Laravel's Eloquent relationships and enforced constraints at the schema level to prevent orphaned records.",[150,355,357],{"className":152,"code":356,"language":154,"meta":155,"style":155},"# php\n# app\u002FModels\u002FInternship.php\npublic function industry()\n{\n    return $this->belongsTo(Industry::class);\n}\n\npublic function teacher()\n{\n    return $this->belongsTo(Teacher::class);\n}\n",[51,358,359,363,368,380,384,404,408,412,423,427,444],{"__ignoreMap":155},[159,360,361],{"class":161,"line":162},[159,362,166],{"class":165},[159,364,365],{"class":161,"line":169},[159,366,367],{"class":165},"# app\u002FModels\u002FInternship.php\n",[159,369,370,372,374,377],{"class":161,"line":175},[159,371,179],{"class":178},[159,373,183],{"class":182},[159,375,376],{"class":182}," industry",[159,378,379],{"class":189},"()\n",[159,381,382],{"class":161,"line":199},[159,383,202],{"class":189},[159,385,386,388,391,393,396,398,401],{"class":161,"line":205},[159,387,215],{"class":214},[159,389,390],{"class":189}," $this-",[159,392,294],{"class":214},[159,394,395],{"class":182},"belongsTo",[159,397,190],{"class":189},[159,399,400],{"class":178},"Industry::class",[159,402,403],{"class":189},");\n",[159,405,406],{"class":161,"line":211},[159,407,232],{"class":189},[159,409,410],{"class":161,"line":229},[159,411,239],{"emptyLinePlaceholder":238},[159,413,414,416,418,421],{"class":161,"line":235},[159,415,179],{"class":178},[159,417,183],{"class":182},[159,419,420],{"class":182}," teacher",[159,422,379],{"class":189},[159,424,425],{"class":161,"line":242},[159,426,202],{"class":189},[159,428,429,431,433,435,437,439,442],{"class":161,"line":248},[159,430,215],{"class":214},[159,432,390],{"class":189},[159,434,294],{"class":214},[159,436,395],{"class":182},[159,438,190],{"class":189},[159,440,441],{"class":178},"Teacher::class",[159,443,403],{"class":189},[159,445,446],{"class":161,"line":275},[159,447,232],{"class":189},[449,450,451],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .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 .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":155,"searchDepth":169,"depth":169,"links":453},[454,455,456],{"id":12,"depth":169,"text":13},{"id":20,"depth":169,"text":21},{"id":73,"depth":169,"text":74,"children":457},[458,459],{"id":78,"depth":175,"text":79},{"id":139,"depth":175,"text":140},"A centralized platform for managing vocational school internships, featuring a robust Admin Dashboard built with Filament PHP and RESTful APIs for student mobile apps.","2 months","md",false,"https:\u002F\u002Fgithub.com\u002Fszuryuu\u002Finternship-monitoring-laravel","\u002Fimages\u002Fprojects\u002Flaravel.png",null,{},"\u002Fproject\u002Finternship-monitoring",{"title":5,"description":460},"Completed","project\u002Finternship-monitoring",[473,42,474,475],"Laravel 11","MySQL","Vue.js","Exam Project","2025","HzvV3BZx9MZrwmJEzQ1537blF_fOySMhmLt5S8C_YCc",1776582962962]