Rekstrarkerfið
Kerfið er skrifað í hreinu JavaScript frá vafra til gagnagrunns, án framendaramma og án build-skrefs, svo það þarf ekki að skipta því út eftir nokkur ár. Allt hér fyrir neðan er tekið úr kóðanum og hýsingunni.
Yfirfarið á móti kóðanum 19. september 2026 · Allt sem hér stendur er eins og það keyrir á rekstrarkerfi.is
Eitt forrit og einn gagnagrunnur
Allir viðskiptavinir keyra sama kjarnann. Í honum eru vefur, verslun, sölukassi, bókhald, notendur og aðgangsstýring, allt í einu Express-forriti ofan á einum PostgreSQL-gagnagrunni. Ekkert er samstillt á milli undirkerfa því þau eru engin. Sala á kassanum og bókhaldsfærslan sem fylgir henni eru raðir í sama gagnagrunninum.
Það sem er sérstakt fyrir einn rekstur er skrifað sem viðbót við hliðina á kjarnanum og breytir ekki skrám hans, þannig að uppfærsla á kjarnanum skrifar ekki yfir það. Breytingar á skema gagnagrunnsins eru migrations í einum röðuðum lista í kóðasafninu og hver þeirra er keyrð í sinni eigin transaction. Migrations í nýrri útgáfu verða að ganga með kóða útgáfunnar á undan. Dálki er bætt við í einni útgáfu og sá gamli fjarlægður í seinni útgáfu, og þess vegna er hægt að setja fyrri Docker-mynd aftur inn.
- vafri · Hreinir ES modules, enginn rammi og ekkert build-skref. Það sem er í kóðasafninu er það sem vafrinn hleður.
- App Service · gámur · Azure App Service sem keyrir Docker-mynd, í Sweden Central. node:24-alpine fest með sha256 digest, keyrir sem notandi án root-réttinda og npm er fjarlægt úr myndinni sem keyrir.
- Express · millilög · Eitt CommonJS-forrit. Röð millilaganna er talin upp í 4. kafla.
- PostgreSQL 16 · Azure Database for PostgreSQL. TLS er skilyrði og gagnagrunnurinn er varinn með eldvegg og auðkenningu.
- build · Trivy · GitHub Actions þar sem hvert action er fest við commit SHA. Docker-myndin er skönnuð með Trivy og útgáfan stöðvast ef Trivy finnur eitthvað sem er merkt HIGH eða CRITICAL.
- prufuumhverfi · Afrit af raunumhverfinu, uppfært vikulega, með sömu uppbyggingu og sömu SKU. Hér er breyting skoðuð fyrst.
- raunumhverfi · Forritið er fest við sama digest og prufuumhverfið keyrði og endurræst. Síðan er kallað á /ready þangað til nýja ferlið svarar.
- fyrri útgáfa · Fyrri myndir eru áfram geymdar. Að bakka er að festa forritið aftur við fyrra digest.
Mynd 1. Leið beiðni (A) og leið útgáfu (B) eins og þær eru í dag.
Hver breyting er yfirfarin
Kóðinn er skrifaður með Claude-líkönum frá Anthropic og hver breyting er yfirfarin áður en hún er sameinuð aðalgreininni. Samningurinn er við Orange Smiley ehf. og það breytir engu um ábyrgðina hvaða verkfæri sló kóðann inn.
Það er gert ráð fyrir mistökum, bæði hjá líkönum og fólki, og þess vegna er engri einni vörn treyst. Sjálfvirk próf, kóðayfirferð, öryggisreglur á hverri beiðni, prufuumhverfi á undan raunumhverfi og vöktun eftir á grípa hvert um sig það sem annað missir af.
- Útgáfur · Hver útgáfa keyrir fyrst í prufuumhverfi og fer svo óbreytt í raunumhverfi. Alltaf er hægt að bakka í fyrri útgáfu.
- Yfirferð · Hver breyting fer í kóðayfirferð og hvert atriði sem hún finnur er lagað eða rökstutt skriflega áður en breytingin er sameinuð aðalgreininni.
- Ferlið hér · SECURE_SDLC.md í kóðasafninu, kortlagt á móti NIST SSDF 1.1, OWASP SAMM 2.0 og ASVS 4.0 á stigi 1 og 2.
- Líkön · Claude-líkön frá Anthropic skrifa kóðann og prófa hann.
Tækni sem endist
Valið til að vera óspennandi. Hvaða Node-forritari sem er getur lesið þennan kóðagrunn á fyrsta degi og ekkert af þessu þarf að skipta út eftir tvö ár.
Grunnur
- Node.js 24 LTS · node:24-alpine, fest með sha256 digest, þannig að nýtt build getur ekki dregið inn annað keyrsluumhverfi.
- Express 5 · Eitt CommonJS-forrit. Margir þekkja það og það breytist hægt.
- PostgreSQL 16 · Eina gagnageymslan. Aðgangur í gegnum pg 8 með parameterised queries, enginn ORM.
- Frontend ES modules · Enginn rammi, enginn bundler, ekkert build-skref. Það er ekkert sem þarf að flytja sig af seinna. Á móti kemur að venjurnar eru okkar eigin og þær þarf að læra.
Innskráning
- lucia 3 · Lotur á þjóninum, geymdar í Postgres. Þetta er eina auðkenningarleiðin og ekkert JWT-lag er til.
- oslo/password scrypt · Stöðluð scrypt-stilling og samanburður í föstum tíma.
- arctic 3 · Google-innskráning, authorization code með PKCE. Hægt er að slökkva á henni með einni umhverfisbreytu.
Varnir
- helmet 8 · CSP, HSTS og hinir svarhausarnir sem eru taldir upp í 4. kafla.
- csrf-csrf 4 · Double-submit token bundið við auðkenni lotunnar, sent í X-CSRF-Token hausnum.
- express-rate-limit 8 · Almenn takmörk og þrengri á innskráningu, endurstillingu lykilorðs, samskiptaforminu og greiðsluferlinu.
- sanitize-html · hpp 2 · 0 · HTML er hreinsað úr öllum strengjum í body beiðninnar. Rich-text reitir fara í gegnum allow-list.
Rekstur
- pino 10 · Loggar á JSON-sniði. Reitir með lykilorðum, token, vafrakökum og kennitölum eru máðir út.
- Docker multi-stage · Notandi án root-réttinda, npm og corepack fjarlægð úr myndinni sem keyrir, HEALTHCHECK á /health.
- stripe 22 · Kortagreiðslur. Undirskrift webhook-kalla er sannreynd á móti hráu body.
Kerfið er beint háð 28 pökkum í keyrslu og npm audit --omit=dev skilaði 0 þekktum veikleikum 19. september 2026. Nákvæmar útgáfur eru festar í kóðasafninu og fást við yfirferð.
Aðgangur er athugaður á þjóninum
Hver beiðni fer í gegnum þessi lög áður en hún nær í gögn. Aðgangur er alltaf athugaður á þjóninum. Route guards í vafranum eru til þæginda og verja ekkert.
- pino-http · Aðgangsloggur á JSON-sniði. Viðkvæmir reitir eru máðir út.
- helmet · Svarhausarnir sem eru taldir upp hér að neðan.
- cors · Allow-list yfir origins, lesinn úr ALLOWED_ORIGINS. Þjónninn ræsir ekki ef breytuna vantar.
- hpp · Endurteknum query-færibreytum er steypt saman í eina.
- express.json · Stærðarmörk eru á öllum beiðnum.
- sanitizeBody · HTML hreinsað úr öllum strengjum. Rich text fer í gegnum allow-list í sanitize-html.
- globalLimiter · Hraðatakmörkun á öllum beiðnum og strangari mörk á innskráningu, endurstillingu lykilorðs og samskiptaformi.
- X-Request-ID · Request id og trace id eru sett á hvert svar áður en nokkuð annað getur svarað. Auðkennið er geymt með hverri villu sem er skráð.
- dbCircuitBreaker · Þegar gagnagrunnurinn er að bregðast er API-köllum hafnað strax svo þau hlaðist ekki upp.
- requireAuth → requireRole → CSRF · Lota, svo hlutverk, svo CSRF-token á skrifum frá innskráðum notendum. Allir admin-routerar athuga lotu og hlutverk, og CSRF á öllu sem skrifar.
- errorHandler · Eitt villusnið, {error, code}. Skilaboð 5xx-villu eru aldrei send til biðlarans.
Hausarnir eins og þjónninn sendir þá. Þú getur sannreynt þá með curl -sI https://rekstrarkerfi.is
- Content-Security-Policy (stytt) · default-src 'self'; script-src 'self'; script-src-attr 'none'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; object-src 'none'; frame-ancestors 'self'; report-uri /csp-report
- Strict-Transport-Security · max-age=31536000; includeSubDomains
- Cross-Origin-Opener-Policy · same-origin
- Cross-Origin-Resource-Policy · same-site
- Referrer-Policy · no-referrer
- X-Content-Type-Options · nosniff
- Set-Cookie: auth_session · HttpOnly; Secure; SameSite=Strict
Lykilorð eru aldrei geymd
Öll auðkenning fer í gegnum Lucia á þjóninum. Taflan sýnir hvað gerist við innskráningu og hvernig aðgangi er skipt.
- Lotur · Geymdar í Postgres. Gilda í 30 daga og eru framlengdar þegar gildistíminn er meira en hálfnaður. Endurstilling lykilorðs eða lokun aðgangs endar allar lotur þess notanda.
- Lykilorð · scrypt. Aðgangur læsist tímabundið eftir endurteknar rangar tilraunir. Óþekkt notandanafn kostar sömu tætivinnu, þannig að svartíminn segir ekki til um hvort aðgangur sé til.
- Tveggja þátta · TOTP, og stjórnandi fær ekki stjórnendaaðgang fyrr en hann hefur virkjað það. Engin lota verður til fyrr en kóðinn er staðfestur. Áskorunin rennur fljótt út og ógildist eftir nokkra ranga kóða, og notaðan kóða er ekki hægt að nota aftur. Tíu einnota endurheimtarkóðar, geymdir sem scrypt-tætigildi. Stjórnendum er hafnað á innskráningu með Google og með tengli, svo hvorug verði notuð til að komast fram hjá seinni þættinum.
- Hlutverk · Millilögin requireRole og requireView á leiðunum. Hlutverk eru gögn og geta fylgt skipulagi viðskiptavinarins sjálfs.
- SQL · Placeholders ($1, $2) alls staðar. Einu hlutarnir sem eru settir beint inn í strenginn eru röðunardálkar sem er flett upp í allow-list.
- Upphleðsla · Allow-list yfir MIME-tegundir. Skráarendingin er ákveðin út frá tegundinni og aldrei út frá skráarnafninu, og stærðarmörk eru á hverri skrá.
- Secrets · Tilvísanir í Azure Key Vault sem managed identity forritsins leysir upp. Hvert forrit getur aðeins lesið sitt eigið vault, og myndir eru sóttar með auðkenni forritsins, ekki lykilorði.
Alltaf hægt að bakka
Útgáfa er GitHub Actions keyrsla sem er sett handvirkt af stað. Docker-myndin er byggð einu sinni fyrir hvert commit og skönnuð með Trivy. Prufuumhverfið keyrir hana fyrst, fest eftir sha256 digest, og þegar /ready svarar þaðan er myndin merkt prófuð. Raunumhverfið fær nákvæmlega sömu mynd og byggir aldrei sjálft.
Forritinu er bakkað með því að festa það aftur við fyrra digest. Migrations sem hafa verið keyrðar eru ekki teknar til baka, og þess vegna verða þær að ganga með kóða útgáfunnar á undan.
Azure tekur afrit af gagnagrunninum með point-in-time restore 14 daga aftur í tímann og afritið er geo-redundant.
Í kjarnanum er líka eining fyrir sjálfvirkar uppfærslur. Uppsetning les manifest yfir HTTPS frá hýsli á allow-list, sækir Docker-myndina eftir sha256 digest, bíður eftir viðhaldsglugga sem viðskiptavinurinn velur, hafnar útgáfu sem krefst nýrri útgáfu en þeirrar sem uppsetningin keyrir og sannreynir sjálfa sig eftir ræsingu. Einingin er smíðuð og prófuð, og kveikt verður á henni þegar útgáfurásin er komin upp, fyrst á okkar eigin vefjum og síðan hjá viðskiptavinum.
Prófað á raunverulegum gagnagrunni og vaktað
Jest-samþættingarprófin keyra á móti raunverulegum PostgreSQL sem er hent og byggður upp aftur úr allri migration-keðjunni í hverri keyrslu, og pg er aldrei mockað. Playwright keyrir heilar notendaferðir í Chromium á móti eigin einnota gagnagrunni fyrir hvert branch. Skemapróf athugar að allar töflur sem SQL-ið vísar í séu til. ESLint keyrir við hvert commit og push í gegnum git hooks.
Sjálfvirkar athuganir keyra á CI-þjóni við hverja sameiningarbeiðni (pull request): úttekt á ytri pökkum, ESLint, athugun á þýðingarlyklum, einingapróf, hluti samþættingarprófanna og smíði gámamyndarinnar fyrir raunumhverfi, sem er ræst á móti tómum gagnagrunni. Öll samþættingarprófin og Playwright-prófin keyra á nóttunni þegar eitthvað nýtt hefur bæst við. Þá keyrslu má líka ræsa í höndunum fyrir útgáfu. Vinnureglan er sú að áður en útgáfa sem bætir við migrations er sett út sé kerfið ræst á móti tómum gagnagrunni til að sannreyna að öll keðjan keyrist.
Villur á þjóni (5xx) og villur í vafra (ógripnar exceptions og promise sem er hafnað) eru skráðar í gagnagrunninn með request id, geymdar í 90 daga og sýndar á stjórnendasíðu. Availability test í Azure kallar á vefinn á fimm mínútna fresti allan sólarhringinn, og viðvaranir um hrinu af 5xx-svörum eða viðvarandi hæg svör eru sendar í tölvupósti. /health svarar fyrir ferlið og /ready fyrir gagnagrunninn.
Hver viðskiptavinur í eigin umhverfi
Hver uppsetning er sett upp eftir sama sniðmáti í Azure. Taflan sýnir hvað hver viðskiptavinur hefur út af fyrir sig og hvað er sameiginlegt.
- Staðsetning · Microsoft Azure, Sweden Central. Innan EES.
- Hver viðskiptavinur · Eigin resource group, App Service plan, PostgreSQL-þjónn, Key Vault og storage account. Viðskiptavinir deila hvorki gagnagrunni, reikniafli né secrets.
- Sameiginlegt · Kóðagrunnur kjarnans, sem allar uppsetningar eru byggðar úr.
- Gagnaflutningur · Eingöngu HTTPS, TLS 1.2 eða nýrra, og HSTS. Gagnagrunnurinn krefst TLS og er varinn með eldvegg og auðkenningu.
- Eignarhald · Gögnin eru eign viðskiptavinarins.
- Afhending gagna · Viðskiptavinur fær gögnin sín afhent bæði sem pg_dump af gagnagrunninum og sem CSV-skrár.
- Gervigreind og gögn · Gögn viðskiptavinar fara ekki til Anthropic nema hann biðji sjálfur um API- eða MCP-tengingu við Claude.
Ákvarðanir og það sem kemur næst
Þetta eru ákvarðanir sem við tókum með ráðum og það sem er næst á dagskrá.
- CI · Sjálfvirkar athuganir keyra við hverja sameiningarbeiðni og öll prófin á nóttunni þegar eitthvað nýtt hefur bæst við. Útgáfur eru settar út í höndunum.
- Útgáfurás · Sjálfvirkar uppfærslur eru smíðaðar og kveikt verður á þeim þegar útgáfurásin er komin upp, fyrst á okkar eigin vefjum og síðan hjá viðskiptavinum.
- Einingaflögg · Að kveikja og slökkva á sérsmíðuðum einingum í hverri uppsetningu er hannað en hefur ekki verið gefið út.
- Hýsing · Eitt svæði og eitt tilvik. Afrit af gagnagrunninum ná 14 daga aftur í tímann og eru geymd á fleiri en einu svæði, og fyrri útgáfa er alltaf til taks.
- Opinbert API · Ekkert enn. MCP-tengi er til, eingöngu með lesaðgang, og slökkt er á því.
Vefurinn þinn mun líta vel út
Hönnun er ekki lokaskref sem er bætt ofan á kerfið. Hún er hluti af hverri síðu frá byrjun. Vefurinn þinn fær sitt eigið útlit, með litum, letri og myndum fyrirtækisins, á grunni sem er þegar vandaður. Það sama á við um stjórnborðið sem starfsfólkið notar á hverjum degi. Það á að vera skýrt, rólegt og fljótlegt að rata um.
Á bak við þetta er fólk sem hefur hannað bæði rými og viðmót, allt frá kaffihúsi í Vestmannaeyjum til viðmóta sem viðskiptavinir Microsoft nota. Þú þarft ekki að taka okkur á orðinu. Síðan sem þú ert að lesa er gerð á sama hátt.
Spurningar og svör
Gervigreind skrifar kóðann. Hver ber ábyrgð þegar eitthvað bilar?
Orange Smiley ehf. Samningurinn er við fyrirtækið og það skiptir engu hvaða verkfæri skrifaði kóðann. Hver breyting er yfirfarin áður en hún er sameinuð aðalgreininni. Ef eitthvað bilar er hægt að setja fyrri útgáfu aftur inn á meðan gallinn er lagaður.
Hvað grípur mistök, hvort sem gervigreind eða forritari gerir þau?
Forritarar gera það líka, og þess vegna eru varnirnar í lögum og engin þeirra þarf að vera gallalaus. Próf keyra á móti raunverulegum PostgreSQL og heilar notendaferðir eru prófaðar í vafra. Útgáfa fer í prufuumhverfi á undan raunumhverfi og eftir það tekur vöktunin við. Migrations eru skrifaðar í tveimur skrefum svo að áfram sé hægt að bakka.
Af hverju ekki áskriftarverslun og sér bókhaldskerfi?
Fyrir mörg fyrirtæki er það alveg nóg og þá er engin ástæða til að skipta. Þetta kerfi er fyrir þau sem eru farin að stemma tölur af á milli kerfa í höndunum, eða þurfa breytingu sem ekkert app býður upp á. Hér er allt í einum gagnagrunni og því ekkert sem þarf að halda samstilltu. Breytingar eru hluti af þjónustusamningnum og eru metnar áður en nokkur vinna hefst.
Bilar sérsmíðin mín við næstu uppfærslu?
Sérsmíði er skrifuð við hliðina á kjarnanum og breytir ekki skrám hans, þannig að uppfærsla skrifar ekki yfir hana. Ef hún þarf breytingar á gagnagrunninum þá bæta þær eingöngu við. Hún er keyrð á móti nýja kjarnanum í prufuumhverfinu áður en útgáfan fer í raunumhverfi, og ef eitthvað fer samt úrskeiðis er fyrri útgáfa sett aftur inn.
Af hverju ekkert React eða annar rammi? Er þetta þá ekki bara heimasmíðað?
Framendinn er ES modules og DOM, án bundlers, og það er með ráðum gert. Kerfi sem á að endast í mörg ár þarf þá hvorki að uppfæra ramma né halda við build-keðju sem úreldist, og færri pakkar sem kerfið er háð þýða minni flöt fyrir supply-chain árásir. Öryggishlutarnir koma úr þekktum söfnum: Lucia fyrir lotur, helmet fyrir CSP, csrf-csrf, express-rate-limit og sanitize-html.
Hvar eru gögnin og hver kemst í þau?
Í Microsoft Azure í Svíþjóð, innan EES. Hver viðskiptavinur er með eigin uppsetningu og eigin gagnagrunn. Aðgangur fer eftir hlutverkum, stjórnendur skrá sig inn með tveggja þátta auðkenningu og það sem stjórnendur gera er skráð.
Hvernig kemst ég út og á hvaða formi fæ ég gögnin?
Gögnin eru eign viðskiptavinarins og þau eru öll í einum PostgreSQL-gagnagrunni sem enginn annar deilir. Þau eru afhent bæði sem pg_dump og sem CSV-skrár, þannig að annað kerfi eða annar forritari getur tekið við þeim.
Fara gögn viðskiptavina inn í gervigreindina?
Nei, ekki nema viðskiptavinurinn biðji um það. Gögn fara aðeins til Anthropic ef viðskiptavinur óskar sjálfur eftir API- eða MCP-tengingu við Claude. Breytingar eru smíðaðar og prófaðar í prufuumhverfi, sem er afrit af raunumhverfinu og uppfært vikulega.
Sendu okkur spurninguna ef svarið er ekki hér. Við svörum henni og bætum svarinu á síðuna.
Sjá verðskrá →
Fáðu demo