Receptakuten

Frontend

Frontenden är utvecklad i Vue.js 3 med Composition API och bygger på en komponentbaserad arkitektur där återanvändbarhet, tydlig ansvarsfördelning och underhållbar kod har varit centrala designprinciper genom hela projektet.

Applikationen består av ett stort antal specialiserade komponenter för bland annat recept, ingredienshantering, gruppadministration, matscheman, profiler, formulär, dialogrutor och navigering. Genom att dela upp funktionaliteten i mindre komponenter har samma komponenter kunnat återanvändas på flera ställen i applikationen, vilket minskar kodduplicering och förenklar vidareutveckling.

Affärslogiken hålls i stor utsträckning separerad från presentationslagret genom egna composables och serviceklasser. Kommunikation mellan komponenter sker främst via props och emitters, medan globala händelser hanteras med en central EventBus. Detta används exempelvis för att uppdatera olika delar av användargränssnittet när data förändras eller när notifieringar behöver visas utan att komponenterna känner till varandra.

Projektet är uppbyggt med en tydlig mappstruktur där komponenter, vyer, composables, API-tjänster och routing hålls åtskilda. Detta gör projektet mer skalbart och enklare att underhålla när nya funktioner läggs till.

Routing och autentisering

Navigeringen hanteras med Vue Router där olika layouts används beroende på användarens autentiseringsstatus. Publika sidor, såsom inloggning, registrering och återställning av lösenord, använder en separat layout från den del av applikationen som kräver inloggning. På så sätt hålls användarupplevelsen enkel innan användaren loggat in samtidigt som den inloggade delen av applikationen kan erbjuda sidomenyer, navigering och användarspecifika funktioner.

Auth layout

Account layout

Kommunikation med backend

All kommunikation med backend sker via ett REST-API genom ett separat servicelager. Genom att samla API-anrop på ett ställe blir komponenterna enklare och mer fokuserade på presentation.

För att förbättra prestandan lagras viss information lokalt i klienten för att minska mängden upprepade API-anrop. Detta ger kortare laddningstider och gör att användaren upplever applikationen som snabbare och mer responsiv.

Flera funktioner bygger på att affärslogiken ligger i backend istället för i klienten. Ett exempel är genereringen av matscheman där backend ansvarar för slumpalgoritmen. Algoritmen ser till att samma recept inte väljs flera gånger under samma vecka och att variationen ökar i takt med att fler recept finns tillgängliga. Genom att placera denna logik i backend säkerställs att alla klienter får samma resultat och att reglerna inte kan kringgås.

Exempel på logiken i backend:

Realtidskommunikation

Applikationen använder Server-Sent Events (SSE) för att skapa realtidsfunktionalitet. När användaren är inloggad lyssnar klienten kontinuerligt efter händelser från servern utan att behöva göra återkommande polling-anrop.

Denna lösning används bland annat för gruppinbjudningar. När en användare blir inbjuden till en grupp visas informationen direkt i gränssnittet utan att sidan behöver laddas om. Detta bidrar till en mer responsiv och modern användarupplevelse.

Profilsida

Varje användare har en profilsida där kontot kan administreras. Här kan användaren bland annat:

  • ändra personlig information
  • byta lösenord
  • se hur många grupper man är medlem i
  • se hur många recept man har delat
  • anpassa applikationens tema
  • hantera övriga kontoinställningar

Genom att samla all kontohantering på ett ställe blir det enkelt för användaren att administrera sitt konto.

Användarupplevelse

Stor vikt har lagts vid att skapa ett snyggt och responsivt gränssnitt. Datumhantering sker med komponenten VueDatePicker, vilket ger ett betydligt mer användarvänligt sätt att välja datum vid exempelvis planering av matscheman.

Applikationen innehåller även automatisk konvertering av HEIC-bilder via Heic2any innan uppladdning. Browser-image-compression används för att se till att bilden inte är förstor innan den skickas till backend, men även backend kollar formatet, komprimerar och optimiserar bilden ytterligare så att det inte går att kringå i frontend.Detta gör att användare, framför allt från iPhone och andra Apple-enheter, kan ladda upp receptbilder utan att själva behöva konvertera filformatet (för att det ska kunna visas i alla webbläsare).

För att göra applikationen mer personlig kan användaren även växla mellan olika teman.

Gränssnittet använder dessutom laddningsindikatorer vid längre operationer samt tydliga återkopplingar när en åtgärd lyckas eller misslyckas. Detta gör att användaren alltid får tydlig feedback på vad som händer.

Applikationen är även responsivt uppbyggd och fungerar på både dator, surfplatta och mobiltelefon.

Behörigheter och säkerhet

Behörighetskontroller utförs alltid i backend. Frontenden använder den information som returneras för att visa eller dölja funktioner beroende på användarens rättigheter, men alla kritiska kontroller verifieras på serversidan.

Exempelvis kan endast gruppens ägare bjuda in nya medlemmar eller ta bort befintliga medlemmar. Även om någon skulle försöka manipulera klienten kommer backend att neka otillåtna åtgärder.

Åtkomst till receptbilder kontrolleras också av backend. Bilder kan endast visas av receptets ägare eller av användare som är medlem i en grupp där receptet har delats.

Delning av recept

När ett recept delas inom en grupp skapas en separat entitet i backend istället för att flera användare arbetar mot samma databaspost. Denna lösning gör det möjligt för användare att skapa egna kopior av delade recept och fortsätta utveckla dem utan att originalreceptet påverkas. På så sätt kan recept delas mellan användare samtidigt som varje användare behåller möjligheten att göra egna ändringar.

Kodkvalitet och skalbarhet

Projektet har utvecklats med fokus på långsiktig underhållbarhet. Genom den komponentbaserade arkitekturen, återanvändbara composables, ett separat API-lager och en tydlig projektstruktur är det enkelt att lägga till nya funktioner utan att påverka befintlig kod.

Sidor laddas dynamiskt via Vue Router (lazy loading) för att minska den initiala laddningstiden, och återanvändbara komponenter används genom hela applikationen för att skapa ett enhetligt gränssnitt och minska mängden duplicerad kod.

Denna arkitektur har gjort det möjligt att successivt bygga ut projektet med nya funktioner utan att behöva göra större förändringar i den befintliga kodbasen.