[{"data":1,"prerenderedAt":837},["ShallowReactive",2],{"navigation":3,"/projects/crm-platform":14,"/projects/crm-platform-surround":831},[4],{"title":5,"path":6,"stem":7,"children":8,"page":13},"Blog","/blog","blog",[9],{"title":10,"path":11,"stem":12},"My Experience as a Junior Software Engineer (First Year)","/blog/my-experience-as-a-junior-software-engineer","blog/my-experience-as-a-junior-software-engineer",false,{"id":15,"title":16,"body":17,"buttonLabel":815,"date":816,"description":817,"extension":818,"image":819,"meta":820,"navigation":338,"path":821,"seo":822,"stem":823,"tags":824,"__hash__":830},"projects/projects/crm-platform.md","Enterprise CRM Platform for Advertising Sales",{"type":18,"value":19,"toc":797},"minimark",[20,25,34,40,43,47,54,93,99,101,105,110,115,126,131,142,147,154,160,165,182,187,198,201,206,220,225,236,238,242,246,279,283,288,291,299,306,403,406,411,414,425,431,436,439,465,470,473,484,487,489,493,497,529,533,540,572,574,578,616,618,622,627,630,644,655,660,663,691,697,702,705,716,723,728,739,745,747,751,765,768,782,788,791,793],[21,22,24],"h2",{"id":23},"the-context","THE CONTEXT",[26,27,28,29,33],"p",{},"Summit Media's advertising sales team was managing campaigns across ",[30,31,32],"strong",{},"20+ industries"," using spreadsheets and a legacy platform. Creating proposals, tracking versions, and generating reports was manual and error-prone.",[26,35,36,39],{},[30,37,38],{},"The stakes:"," Ad sales is revenue. Slow tools slow down the entire sales process.",[41,42],"hr",{},[21,44,46],{"id":45},"the-challenge-and-why-it-was-brutal","THE CHALLENGE (And Why It Was Brutal)",[26,48,49,50,53],{},"This was my ",[30,51,52],{},"biggest technical challenge"," to date:",[55,56,57,65,72,79,86],"ul",{},[58,59,60,61,64],"li",{},"⏰ ",[30,62,63],{},"Tight deadlines"," - Fast-paced, production-critical",[58,66,67,68,71],{},"🎯 ",[30,69,70],{},"Solo frontend dev"," - I was responsible for implementing most of the UI/UX, translating provided mockups into a functional system",[58,73,74,75,78],{},"🆕 ",[30,76,77],{},"First-time everything"," - Most patterns were new to me",[58,80,81,82,85],{},"🎨 ",[30,83,84],{},"Complex UI"," - 20+ industry filters, dynamic tables, conditional actions",[58,87,88,89,92],{},"🔗 ",[30,90,91],{},"Heavy API integration"," - Real-time data syncing",[26,94,95,98],{},[30,96,97],{},"Translation:"," I had to learn while building, fast.",[41,100],{},[21,102,104],{"id":103},"what-i-built","WHAT I BUILT",[106,107,109],"h3",{"id":108},"core-features","Core Features:",[26,111,112],{},[30,113,114],{},"1. Campaign Management System",[55,116,117,120,123],{},[58,118,119],{},"Create, track, and manage campaigns across multiple industries",[58,121,122],{},"Real-time cost estimation and proposal generation",[58,124,125],{},"Version control for proposals (sales teams iterate constantly)",[26,127,128],{},[30,129,130],{},"2. Advanced Filtering System",[55,132,133,136,139],{},[58,134,135],{},"20+ industry categories with nested filters",[58,137,138],{},"Search across campaigns, proposals, and cost estimation",[58,140,141],{},"Instant results with performance optimization",[26,143,144],{},[30,145,146],{},"3. Dynamic Table System with Smart Actions",[26,148,149,150,153],{},"This was the ",[30,151,152],{},"heart of the CRM"," and my proudest technical achievement:",[26,155,156,159],{},[30,157,158],{},"The Challenge:"," Different campaign statuses require different actions. A draft proposal needs \"Create Proposal,\" an approved proposal needs \"Create CE,\" a completed campaign needs \"Create Job Order\"—and the UI had to make this intuitive.",[26,161,162],{},[30,163,164],{},"What I Built:",[55,166,167,170,176,179],{},[58,168,169],{},"Multiple interconnected tables (Campaigns, Proposals, Cost Estimate, Job Orders)",[58,171,172,175],{},[30,173,174],{},"Status-driven action system"," - buttons and options that dynamically change based on campaign state",[58,177,178],{},"Complex conditional logic determining what actions are available",[58,180,181],{},"Real-time status updates reflected across all related tables",[26,183,184],{},[30,185,186],{},"Example Flow:",[188,189,194],"pre",{"className":190,"code":192,"language":193},[191],"language-text","Draft → [Edit | Create Proposal]\n  ↓\nProposal → [Create another version | Create CE | Edit | Generate PDF]\n  ↓\nCost Estimate → [Create another version | Create Job Order | Generate PDF]\n  ↓\nJob Order → [Publish | Add Notes | Start Campaign | Stop Campaign]\n  ↓\nCompleted → [Generate Invoice | Archive | View Report]\n","text",[195,196,192],"code",{"__ignoreMap":197},"",[26,199,200],{},"Each status transition triggered different API calls, updated multiple tables, and recalculated related data in real-time.",[26,202,203],{},[30,204,205],{},"Technical Complexity:",[55,207,208,211,214,217],{},[58,209,210],{},"Conditional rendering based on user permissions AND campaign status",[58,212,213],{},"Optimistic UI updates (show changes immediately, sync with backend)",[58,215,216],{},"Cascading updates (changing one campaign affects related proposals, job orders)",[58,218,219],{},"State synchronization across multiple table views",[26,221,222],{},[30,223,224],{},"4. PDF Generation",[55,226,227,230,233],{},[58,228,229],{},"One-click proposal and invoice exports",[58,231,232],{},"Professional formatting with company branding",[58,234,235],{},"Dynamic content based on campaign configuration",[41,237],{},[21,239,241],{"id":240},"the-technical-deep-dive","THE TECHNICAL DEEP DIVE",[106,243,245],{"id":244},"my-responsibilities","My Responsibilities:",[26,247,248,249,252,253,256,257,260,261,256,263,266,267,256,269,272,273,256,275,278],{},"✅ ",[30,250,251],{},"Frontend Architecture"," - Component structure and routing",[254,255],"br",{},"\n✅ ",[30,258,259],{},"UI/UX Implementation"," - Pixel-perfect from Figma designs",[254,262],{},[30,264,265],{},"API Integration"," - RESTful endpoints, state synchronization",[254,268],{},[30,270,271],{},"Business Logic"," - Calculations, validations, conditional flows",[254,274],{},[30,276,277],{},"State Management"," - Pinia for complex, multi-view data",[106,280,282],{"id":281},"hardest-technical-problems","Hardest Technical Problems:",[26,284,285],{},[30,286,287],{},"Problem 1: Status-Dependent Action System",[26,289,290],{},"The most complex part was managing actions that depend on:",[55,292,293,296],{},[58,294,295],{},"Campaign status (Draft, In Progress, For Proposal, Proposal Sent, etc)",[58,297,298],{},"Related data state (Does this campaign have a proposal? cost estimate?)",[26,300,301,302,305],{},"I built a ",[30,303,304],{},"computed action system"," that evaluates all conditions and renders only valid actions:",[188,307,311],{"className":308,"code":309,"language":310,"meta":197,"style":197},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","// Simplified example of the pattern I used\nconst availableActions = computed(() => {\n  const actions = [];\n\n  if (campaign.status === \"draft\" && hasPermission(\"edit\")) {\n    actions.push({ label: \"Edit\", handler: editCampaign });\n  }\n\n  if (campaign.status === \"approved\" && !campaign.hasJobOrder) {\n    actions.push({ label: \"Create Job Order\", handler: createJobOrder });\n  }\n\n  // ... many more conditions\n  return actions;\n});\n","javascript",[195,312,313,321,327,333,340,346,352,358,363,369,375,380,385,391,397],{"__ignoreMap":197},[314,315,318],"span",{"class":316,"line":317},"line",1,[314,319,320],{},"// Simplified example of the pattern I used\n",[314,322,324],{"class":316,"line":323},2,[314,325,326],{},"const availableActions = computed(() => {\n",[314,328,330],{"class":316,"line":329},3,[314,331,332],{},"  const actions = [];\n",[314,334,336],{"class":316,"line":335},4,[314,337,339],{"emptyLinePlaceholder":338},true,"\n",[314,341,343],{"class":316,"line":342},5,[314,344,345],{},"  if (campaign.status === \"draft\" && hasPermission(\"edit\")) {\n",[314,347,349],{"class":316,"line":348},6,[314,350,351],{},"    actions.push({ label: \"Edit\", handler: editCampaign });\n",[314,353,355],{"class":316,"line":354},7,[314,356,357],{},"  }\n",[314,359,361],{"class":316,"line":360},8,[314,362,339],{"emptyLinePlaceholder":338},[314,364,366],{"class":316,"line":365},9,[314,367,368],{},"  if (campaign.status === \"approved\" && !campaign.hasJobOrder) {\n",[314,370,372],{"class":316,"line":371},10,[314,373,374],{},"    actions.push({ label: \"Create Job Order\", handler: createJobOrder });\n",[314,376,378],{"class":316,"line":377},11,[314,379,357],{},[314,381,383],{"class":316,"line":382},12,[314,384,339],{"emptyLinePlaceholder":338},[314,386,388],{"class":316,"line":387},13,[314,389,390],{},"  // ... many more conditions\n",[314,392,394],{"class":316,"line":393},14,[314,395,396],{},"  return actions;\n",[314,398,400],{"class":316,"line":399},15,[314,401,402],{},"});\n",[26,404,405],{},"This kept the UI clean while handling incredibly complex business logic.",[26,407,408],{},[30,409,410],{},"Problem 2: Real-Time Data Synchronization",[26,412,413],{},"Multiple users editing campaigns simultaneously required:",[55,415,416,419,422],{},[58,417,418],{},"Optimistic updates (show changes immediately)",[58,420,421],{},"Conflict resolution when data changes server-side",[58,423,424],{},"Automatic table refreshes without losing user context (filters, sort, pagination)",[26,426,427,430],{},[30,428,429],{},"Solution:"," Built a smart polling system that checks for updates without disrupting user workflow.",[26,432,433],{},[30,434,435],{},"Problem 3: Performance with Large Datasets",[26,437,438],{},"Rendering 100+ campaigns with filters, search, and dynamic actions without lag required:",[55,440,441,447,453,459],{},[58,442,443,446],{},[30,444,445],{},"Virtual scrolling"," for large tables",[58,448,449,452],{},[30,450,451],{},"Debounced search"," inputs (wait 300ms after typing stops)",[58,454,455,458],{},[30,456,457],{},"Optimized computed properties"," (cache results, only recalculate when dependencies change)",[58,460,461,464],{},[30,462,463],{},"Lazy loading"," related data (load job orders only when row is expanded)",[26,466,467],{},[30,468,469],{},"Problem 4: Complex Form Validation",[26,471,472],{},"Campaign creation had interdependent fields:",[55,474,475,478,481],{},[58,476,477],{},"Industry selection → determines available ad types",[58,479,480],{},"Location selection → determines pricing structure",[58,482,483],{},"Pricing changes → recalculates total cost in real-time",[26,485,486],{},"All while maintaining a smooth UX and clear error messages.",[41,488],{},[21,490,492],{"id":491},"the-impact","THE IMPACT",[106,494,496],{"id":495},"for-the-sales-team","For the Sales Team:",[55,498,499,505,511,517,523],{},[58,500,248,501,504],{},[30,502,503],{},"Faster proposal creation"," (estimated 60% time savings)",[58,506,248,507,510],{},[30,508,509],{},"Better version tracking"," (no more \"Final_v3_REAL_Final.xlsx\")",[58,512,248,513,516],{},[30,514,515],{},"Clear action visibility"," - always know what you can do next",[58,518,248,519,522],{},[30,520,521],{},"Professional PDF exports"," for clients",[58,524,248,525,528],{},[30,526,527],{},"Real-time pipeline visibility"," across all campaigns",[106,530,532],{"id":531},"for-me","For Me:",[26,534,535,536,539],{},"This project ",[30,537,538],{},"leveled me up"," as a developer:",[55,541,542,548,554,560,566],{},[58,543,544,547],{},[30,545,546],{},"Learned to work under pressure"," without sacrificing quality",[58,549,550,553],{},[30,551,552],{},"Gained confidence in complex state management"," (Pinia for multi-view data)",[58,555,556,559],{},[30,557,558],{},"Mastered conditional logic"," at scale (status-driven UIs are everywhere now)",[58,561,562,565],{},[30,563,564],{},"Understood how frontend decisions impact business"," (slow CRM = lost revenue)",[58,567,568,571],{},[30,569,570],{},"Discovered I thrive in fast-paced environments"," (tight deadlines became my fuel)",[41,573],{},[21,575,577],{"id":576},"tech-stack","TECH STACK",[55,579,580,586,592,598,604,610],{},[58,581,582,585],{},[30,583,584],{},"Frontend:"," Vue 3 (Composition API), Nuxt 3",[58,587,588,591],{},[30,589,590],{},"State Management:"," Pinia",[58,593,594,597],{},[30,595,596],{},"UI:"," Tailwind CSS",[58,599,600,603],{},[30,601,602],{},"Tables:"," Custom-built with virtual scrolling",[58,605,606,609],{},[30,607,608],{},"PDF:"," API-generated PDFs with in-app modal viewer",[58,611,612,615],{},[30,613,614],{},"API:"," RESTful integration with Node.js backend",[41,617],{},[21,619,621],{"id":620},"what-this-taught-me","WHAT THIS TAUGHT ME",[26,623,624],{},[30,625,626],{},"1. You Don't Need to Know Everything to Start",[26,628,629],{},"Most patterns were new to me:",[55,631,632,635,638,641],{},[58,633,634],{},"Complex state management across multiple views",[58,636,637],{},"Conditional action systems",[58,639,640],{},"Virtual scrolling for performance",[58,642,643],{},"Real-time data synchronization",[26,645,646,647,650,651,654],{},"I used ",[30,648,649],{},"AI tools"," (Claude, ChatGPT) to accelerate learning, but I made sure to ",[30,652,653],{},"understand"," every solution, not just copy-paste. I'd ask \"Why does this pattern work?\" not just \"Give me the code.\"",[26,656,657],{},[30,658,659],{},"2. Clean Code Under Pressure is Possible",[26,661,662],{},"Even with tight deadlines, I prioritized:",[55,664,665,679,685],{},[58,666,667,670,671,674,675,678],{},[30,668,669],{},"Meaningful component names"," (",[195,672,673],{},"CampaignActionButton"," not ",[195,676,677],{},"Button2",")",[58,680,681,684],{},[30,682,683],{},"Clear state structure"," (organized Pinia stores by feature)",[58,686,687,690],{},[30,688,689],{},"Comments on complex logic"," (especially the status-action mapping)",[26,692,693,696],{},[30,694,695],{},"Why?"," Other devs need to maintain this. Rushing today creates problems tomorrow. Plus, clean code is faster to debug when (not if) bugs appear.",[26,698,699],{},[30,700,701],{},"3. Frontend Impacts Revenue",[26,703,704],{},"A slow, buggy CRM doesn't just annoy users—it costs money:",[55,706,707,710,713],{},[58,708,709],{},"Slow filters = sales team wastes time",[58,711,712],{},"Broken action buttons = proposals don't get sent",[58,714,715],{},"Confusing UI = mistakes in pricing",[26,717,718,719,722],{},"This shifted how I think about ",[30,720,721],{},"performance and UX as business priorities",", not just nice-to-haves.",[26,724,725],{},[30,726,727],{},"4. Complex UIs Need Simple Patterns",[26,729,730,731,734,735,738],{},"The status-action system could have been a nightmare of nested ",[195,732,733],{},"if"," statements. Instead, I built a ",[30,736,737],{},"declarative pattern"," that made adding new statuses or actions predictable and safe.",[26,740,741,744],{},[30,742,743],{},"Key principle:"," Make the complex logic look simple in the code.",[41,746],{},[21,748,750],{"id":749},"the-bigger-picture","THE BIGGER PICTURE",[26,752,753,754,757,758,761,762,764],{},"This CRM manages ",[30,755,756],{},"100+ campaigns"," for ",[30,759,760],{},"15+ sales team members"," across ",[30,763,32],{},".",[26,766,767],{},"But more than that, it taught me:",[55,769,770,773,776,779],{},[58,771,772],{},"How to deliver under pressure",[58,774,775],{},"How to learn while building",[58,777,778],{},"How frontend choices impact real business outcomes",[58,780,781],{},"That I love complex, high-stakes projects",[26,783,784,787],{},[30,785,786],{},"This is the project that made me want to learn backend","—because I kept thinking, \"How does the API handle this? Could I build a better sync system?\"",[26,789,790],{},"Now I'm learning Node.js, Express, and database design to answer those questions.",[41,792],{},[794,795,796],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":197,"searchDepth":323,"depth":323,"links":798},[799,800,801,804,808,812,813,814],{"id":23,"depth":323,"text":24},{"id":45,"depth":323,"text":46},{"id":103,"depth":323,"text":104,"children":802},[803],{"id":108,"depth":329,"text":109},{"id":240,"depth":323,"text":241,"children":805},[806,807],{"id":244,"depth":329,"text":245},{"id":281,"depth":329,"text":282},{"id":491,"depth":323,"text":492,"children":809},[810,811],{"id":495,"depth":329,"text":496},{"id":531,"depth":329,"text":532},{"id":576,"depth":323,"text":577},{"id":620,"depth":323,"text":621},{"id":749,"depth":323,"text":750},null,"2025","Mission-critical platform serving 15+ sales team members. Built complex dashboards, filtering systems, and PDF generation. My biggest technical challenge: delivering enterprise features under tight deadlines.","md","/projects/crm.png",{},"/projects/crm-platform",{"title":16,"description":817},"projects/crm-platform",[825,826,827,828,829],"Vue.js","Nuxt.js","Pinia","Tailwind CSS","API integration","psi-OYfWrxFMfHzack2EKqWbbK5vsaVqGGSmT8DJWf0",[815,832],{"title":833,"path":834,"stem":835,"description":836,"children":-1},"Dynamic Content Page Builder","/projects/dynamic-page-builder","projects/dynamic-page-builder","15+ reusable components giving writers creative freedom. Reduced content creation time by 50% and eliminated developer dependencies. Built with Vue 3 & Nuxt 3 component architecture and Pinia state management.",1782865071013]