Grensen som avgjør om en nettbutikk er trygg
pluginfinance.com presenterer og distribuerer utvidelser for finansbransjen. Arbeidet startet i 2012, omfattet også den visuelle identiteten, og første versjon ble laget på omtrent seks uker. Plattformen har siden blitt vedlikeholdt og modernisert, og kjører derfor i dag på PHP 8 og MySQL 8, med WordPress som innholds- og handelslag og et React-grensesnitt som snakker med det over REST og GraphQL.
Det mest konsekvensrike valget i hele prosjektet handler ikke om design, men om hvor mellomlagringen må stoppe. En nettbutikk deler trafikken i to ulike halvdeler. Katalogsider og redaksjonelt stoff er identiske for alle besøkende, så de kan leveres fra kanten av nettet og aldri røre PHP. Handlekurv, kundekonto, ordrehistorikk og listen over lisensnøkler er personlige og skal ikke mellomlagres noe annet sted enn i eierens egen nettleser. Grensen mellom disse to verdenene er den vanligste kilden til alvorlige feil i nettbutikker: én feil satt hode, og kanten begynner å levere én kundes handlekurv til en annen.
Regelen er derfor absolutt og ikke gjenstand for optimalisering: finnes det en informasjonskapsel for handlekurvøkten, er forespørselen utelukket fra mellomlagring på kanten, uten unntak. Det koster hastighet for innloggede kunder, og den prisen betales bevisst, fordi alternativet er lekkasje av ordredata. Fragmenter som avhenger av økten, som telleren i toppfeltet, hentes med en egen forespørsel etter at siden er lastet, slik at selve sidestrukturen forblir felles for alle og fortsatt kan mellomlagres.
Redis forkorter det som blir igjen inne i PHP. I en butikk med mange produktegenskaper kommer den tyngste kostnaden fra spørringer mot metadata, fordi databasen må koble produkter mot egenskaper ved hver eneste filtrering. De resultatene ligger sammen med egenskapslister og kategoristruktur i objektbufferen og invalideres når et produkt endres, ikke når en tidsfrist løper ut.
Her finnes ingen resultattabell. Salgstall tilhører kunden, ikke en porteføljeoppføring hos oss. Det som lar seg vise ærlig, er hvilke valg som ble tatt og hvorfor.
Salget er begynnelsen på forholdet
Handelslaget er WooCommerce, utvidet med abonnement og lisenser. Her ligger den vanskeligste delen av prosjektet, for i kjøpsøyeblikket begynner butikkens arbeid i stedet for å slutte.
Lisensnøkkelen som genereres etter betaling er bare starten. Kundens installasjon spør tjenesten om tilgjengelige oppdateringer, så butikken er samtidig en oppdateringstjener. Det betyr at forespørsler ikke bare kommer fra mennesker med nettleser, men fra hundrevis av WordPress-installasjoner som sjekker i bakgrunnen etter sin egen timeplan, uavhengig av besøkstrafikken. Den trafikken er usynlig i besøksstatistikken og svært synlig i serverlasten hvis ingen har planlagt for den.
Løsningen skiller de to verdenene. Endepunktet som kontrollerer lisens og versjon svarer så kort som mulig, leser fra Redis og starter ikke hele sidelastsyklusen. Selve oppdateringsfilen leveres fra kanten, fordi den er en statisk fil og ikke resultatet av en databasespørring. Å skille rettighetskontrollen fra filleveransen er kjernen: kontrollen må være billig og nøyaktig, mens overføringen er dyr og hører hjemme så langt fra applikasjonen som mulig.
Under dette ligger en regel som høres juridisk ut og ender i kode. En utløpt lisens skal ikke slå av en installert utvidelse. Kunden har betalt for programvare som fortsatt skal virke; utløpet fjerner retten til oppdateringer og støtte, ikke bruksretten. Lisensstatus og driftsstatus må derfor være to uavhengige verdier. Blander man dem, sitter kunden etter den første forsinkede fornyelsen med en avslått modul i produksjon og en feil butikken selv forårsaket.
En produktside som egentlig er et datablad
En finansutvidelse kjøpes på parametre, ikke på et produktbilde. Kjøperen vil vite hvilke versjoner av WordPress og PHP produktet virker med, hvilke eksterne avhengigheter det drar med seg, om det fungerer i en flerspråklig installasjon, hva det gjør med betalingsdata og hvordan støtteveien ser ut etter kjøpet. Ingenting av dette hører hjemme i en brødtekst, fordi alt sammen må kunne filtreres og sammenlignes.
Produktene beskrives derfor med egne innholdstyper og egendefinerte felt bygget på Advanced Custom Fields. En teknisk parameter er et felt, ikke en setning. Den åpenbare gevinsten er filtrering og sortering. Den mindre åpenbare viser seg i vedlikeholdet: når WordPress slipper en ny hovedversjon, er oppdatering av kompatibilitet for hele katalogen én operasjon på ett felt, ikke gjennomlesing av flere titalls beskrivelser på jakt etter setningen som nevner en versjon. En katalog som holder kompatibiliteten i prosa, lyver om halvparten av oppføringene sine etter to år, og ingen legger merke til det.
Sammenligningstabeller avhenger av denne disiplinen mer enn av noe annet. Den som vurderer finansverktøy, snevrer som regel inn til to eller tre kandidater og vil se dem ved siden av hverandre, egenskap mot egenskap. En sammenligning er bare så god som feltene er komplette: står kompatibilitetsfeltet tomt på halvparten av produktene, villeder tabellen mer effektivt enn den hjelper. Feltene som driver sammenligningen er derfor obligatoriske ved publisering, ikke valgfrie.
Omtaler, kundehistorier og fagartikler er egne innholdstyper, og det samme er produktdokumentasjonen. Dokumentasjon har versjoner: installasjonsveiledningen for fjorårets utgivelse kan ikke forsvinne i det øyeblikket en ny kommer, fordi noen kunder bevisst blir værende på en eldre gren.
Hodeløst oppsett, og hva det faktisk koster
Grensesnittet er en applikasjon i nettleseren, med WordPress som innholds- og handelslag bak. Valget hadde en konkret begrunnelse her, og vi anbefaler det ikke refleksmessig for enhver nettbutikk.
Begrunnelsen er flerdimensjonal filtrering. Kjøpere snevrer inn katalogen etter integrasjonstype, versjonskompatibilitet, lisensmodell og flere andre egenskaper, og ombestemmer seg underveis. I den klassiske modellen er hver filterendring en ny sidelasting og en full gjengivelse på tjeneren. I en katalog med mange egenskaper betyr det et titalls databasespørringer per klikk i en avkrysningsboks. Et adskilt grensesnitt henter bare resultatlisten, ikke hele visningen.
Kostnadene er virkelige og bør sies rett ut. Innhold som lages i nettleseren kan være vanskeligere for søkeroboter å se, så sidene som skal hente søketrafikk, altså produktsidene og det redaksjonelle stoffet, gjengis på tjeneren og leveres som ferdig HTML. Bare katalogbetjeningen er klientsidig. Den andre kostnaden er API-laget i seg selv, som blir enda en grense å vedlikeholde og sikre. GraphQL løser en del av problemet, fordi én spørring henter nøyaktig de feltene visningen trenger i stedet for tre REST-kall som hver returnerer for mye, men det krever nøye grenser for spørringskompleksitet. Et offentlig GraphQL-endepunkt uten dybdebegrensning er en invitasjon til å tømme tjeneren med én forespørsel.
Avgiftsregler som rekker inn i handlekurven
Enhver butikk som selger digitale varer over en landegrense møter et krav som ikke er etterarbeid for regnskapet, men en betingelse i selve kjøpsløpet. En elektronisk tjeneste levert til en forbruker i et annet EU-land beskattes etter satsen i kjøperens land, og salg til et foretak med gyldig avgiftsnummer gjøres opp annerledes enn salg til en privatperson. Butikken må altså fastslå kjøperens status før den kan vise en sluttpris, kontrollere nummeret mot registeret og ta vare på dokumentasjon på hvor kjøperen befinner seg.
Det rekker inn i handlekurven og i fakturamalen. Det berører dessuten mellomlagringen på en måte som overrasker mange: en pris som avhenger av besøkendes land, kan ikke bakes inn i en side som er mellomlagret for alle. Prisene i katalogen vises derfor i en definert grunnform, og det landavhengige sluttbeløpet oppstår i handlekurven, der forespørselen uansett er utelukket fra mellomlagring på kanten.
Sikkerhet for et produkt tett på finans
Et nettsted som selger verktøy til finansbransjen er et attraktivt mål av to grunner samtidig: det behandler betalinger og det distribuerer kode som kundene installerer på sine egne nettsteder. Det andre veier tyngst, for en kompromittert oppdateringsfil sprer seg automatisk til alle installasjoner.
Det bestemmer rekkefølgen på tiltakene. Betalinger går ikke gjennom nettstedet, men gjennom betalingsleverandøren, så kortdata når aldri egen tjener, og butikken lagrer bare en transaksjonsreferanse. Utgivelsesfiler er signert og leveres først etter lisenskontroll, og tilgangen til utgivelsespanelet er skilt fra vanlig innholdsadministrasjon. Sikkerhet løses i kode og i tjenerkonfigurasjon, ikke med enda en sikkerhetsutvidelse. En slik utvidelse kjører inne i PHP, altså etter at forespørselen allerede har startet applikasjonen, den koster noe på hver forespørsel, og den viser seg jevnlig å være en sårbarhet i seg selv.
I tillegg kommer et personvernlag som ikke lar seg unngå i en butikk med lisensnøkler. En kundekonto knytter en e-postadresse til listen over domener der lisensene kjører, altså til informasjon om selskapets infrastruktur. Det er ikke særlige kategorier av personopplysninger, men en lekkasje har reelle følger for kunden, fordi den viser en angriper hvilke verktøy som står på hvilket nettsted. Tilgangen til listen er begrenset på API-nivå på samme måte som ordredata, og loggene lagrer bevisst forkortede identifikatorer i stedet for hele lisensnøkler.
Ytelse, overvåking og vedlikehold
Vedlikeholdet i en lisensbutikk har ett punkt som vanlig netthandel ikke har. Hver WordPress-oppdatering på butikksiden må avstemmes mot kompatibiliteten som de solgte produktene oppgir. En butikk som selv kjører nyeste versjon mens den selger utvidelser merket kompatible med en versjon fra to år tilbake, undergraver sin egen katalog før en kunde har lest en linje.
Resten er kjent arbeid: oppdatering av kjerne, tema og utvidelser, gjennomgang av logger og sikkerhetskopier der gjenopprettingen faktisk er prøvd. I tillegg kommer de funksjonelle endringene som følger av hvordan tilbudet utvikler seg, og de lar seg ikke planlegge på forhånd. De er grunnen til at en vedlikeholdsavtale her handler mer om tilgjengelig tid enn om en fast liste med oppgaver.
Testing skjer mot en kopi av produksjonen, aldri mot en tom installasjon, og grunnen er mer bokstavelig enn i de fleste prosjekter. En tom installasjon har ikke én eneste aktiv lisens. Hele logikken rundt fornyelse, utløp og versjonskontroll har dermed ingenting å kjøre mot, og hver test består fordi den ikke har noe å gjøre. Et ekte lisensgrunnlag oppfører seg annerledes, med oppføringer som gikk ut forrige uke, oppføringer fornyet midt i perioden og lisenser en kunde har flyttet mellom domener uten å si fra. Først den blandingen viser om reglene stemmer med det salgsvilkårene lover.
Overvåkingen har derfor én prioritet over alle andre, og det er ikke forsiden. Svartiden til lisensendepunktet avgjør mest, for et endepunkt som slutter å svare koster ikke et salg, det får hundrevis av kundeinstallasjoner til å melde oppdateringsfeil i samme minutt og gir støtteapparatet en bølge av henvendelser om en feil som aldri skjedde hos kunden.
Trafikken fra de installasjonene dukker ikke opp i noen besøksstatistikk, bare i serverlasten, og den går etter sin egen rytme uavhengig av hva folk gjør på nettstedet. Alt som ligger foran endepunktet er vanlig arbeid med grensesnittet. Ressurser kompileres, pakker deles opp, kode lastes bare på sidene som bruker den, og bilder behandles én gang ved opplasting i stedet for ved hver visning. Statiske filer går gjennom Cloudflare, som med kunder spredt over flere verdensdeler er den største enkeltbesparelsen.
Oppsummering
WordPress bærer programvaredistribusjon så lenge det behandles som innholds- og handelslag og ikke som hele applikasjonen. Utenfor hører det som har harde krav til tid eller sikkerhet, her altså to ting: lisenskontrollen og filleveransen. Resten ligger der et publiseringssystem er sterkt. Katalogen, den versjonerte dokumentasjonen, det redaksjonelle stoffet og kassen bor i samme installasjon uten å komme i veien for hverandre. Fire valg overføres til neste prosjekt av samme type: strukturerte produktdata i stedet for løpende tekst, skillet mellom bruksrett og oppdateringsrett, en uttalt grense rundt det som kan mellomlagres, og delingen av lisenskontroll og filleveranse.
Det som ikke overføres, er innholdsmodellen i denne katalogen og lisensreglene, skrevet for ett tilbud og ett sett vilkår. En leverandør som selger evig bruksrett og tidsbegrenset støtte hver for seg, trenger en annen form fra første felt. Så hvor begynner neste leveranse, hvis ikke i en mal? I spørsmålet om hva kunden nøyaktig kjøper og for hvor lenge, fordi svaret avgjør halve arkitekturen før noen åpner en editor.
Ofte stilte spørsmål
Praktiske svar for å bruke temaet i faktisk arbeid.
Hvilket omfang hadde prosjektet pluginfinance.com?
#Hvordan gikk leveransen for pluginfinance.com?
#Hva var hardest teknisk i pluginfinance.com?
#Hvilken del av pluginfinance.com kan gjenbrukes på et nytt bygg?
#Trenger du FAQ tilpasset bransje og marked? Vi lager en versjon som støtter dine forretningsmål.
Ta kontakt