# Bucket & Code Server IDE: användarhandbok

Bucket & Code Server IDE (QPKG `bucketvs`) förvarar källkod och filer på en QNAP-NAS och bygger programvara där.
Paketet har en egen webbserver, egna verktyg och egna konton.

Den här handboken beskriver paketet så som det körs på NAS:en.

## Innehåll

- [Vad som körs på NAS:en](#vad-som-körs-på-nasen)
- [Installera paketet](#installera-paketet)
- [Första inloggningen](#första-inloggningen)
- [Arbeta i panelen](#arbeta-i-panelen)
- [Konton](#konton)
- [Datamappen](#datamappen)
- [Nätverk](#nätverk)
- [Bakom en omvänd proxy (Plesk)](#bakom-en-omvänd-proxy-plesk)
- [Värdnamn för modulerna](#värdnamn-för-modulerna)
- [Publicera på internet (Cloudflare Tunnel)](#publicera-på-internet-cloudflare-tunnel)
- [Moduler](#moduler)
- [Git](#git)
- [CI-runners](#ci-runners)
- [SVN och Bucket](#svn-och-bucket)
- [Redigerare och AI-verktyg](#redigerare-och-ai-verktyg)
- [Verktygskedjor och miljöer](#verktygskedjor-och-miljöer)
- [App Builder](#app-builder)
- [Paketrepository](#paketrepository)
- [Kärnverkstaden](#kärnverkstaden)
- [Cron-jobb och operationer](#cron-jobb-och-operationer)
- [Säkerhetskopior](#säkerhetskopior)
- [Aviseringar](#aviseringar)
- [Loggar och supportpaketet](#loggar-och-supportpaketet)
- [Uppdateringar](#uppdateringar)
- [Kommandot bvs](#kommandot-bvs)
- [Filer och mappar](#filer-och-mappar)

## Vad som körs på NAS:en

| Del | Vad den gör | Var den lyssnar |
|---|---|---|
| nginx | den enda dörren på LAN:et: serverar panelen och skickar varje sökväg vidare till sin modul | 9950 (HTTP), 9951 (HTTPS) |
| bvsd | startar och övervakar alla andra processer, håller kontona och inställningarna, kör jobb och cron-jobb, svarar panelen | två Unix-socketar i `/usr/bin/bucketvs/var/run/` |
| Git (Forgejo) | Git-värd med webbgränssnitt | en Unix-socket i `/usr/bin/bucketvs/var/run/forgejo/`, och 9952 för Git via SSH |
| SVN och Bucket (httpd) | Subversion-repositoryn och WebDAV-mappar med historik | 127.0.0.1:9961, eller nästa lediga port när ett annat program har den |
| Redigerare (code-server) | VS Code i webbläsaren, en instans per konto | en Unix-socket per konto i `/usr/bin/bucketvs/var/run/ide/` |
| CI | Forgejo Actions-runnern | ingen egen port; nginx lyssnar åt den på 127.0.0.1:9960 medan modulen är på, eller på nästa lediga port när ett annat program har 9960 |

Kärnan (nginx, bvsd, panelen, cron-jobb, verktygskedjor) är alltid på. Git, CI, SVN och Bucket samt Redigerare är
moduler som en admin slår på och av. På varje adress till NAS:en svarar modulerna under sina sökvägar: `/git/`, `/svn/`,
`/bucket/`, `/ide/`. Panelen finns på `/`, och den här handboken på `/guide/`.

Medan paketet körs finns dess program i `/usr/bin/bucketvs/bin`. Allt som paketet sparar (konton, inställningar,
repositoryn, miljöer, loggar) ligger i en enda mapp på en datavolym: [datamapp](#datamappen).

## Installera paketet

Paketet kräver QTS 6.0 eller QuTS hero 6.0 eller senare, på en NAS med x86_64 eller ARM 64-bit; det finns ett paket
per arkitektur (`bucketvs_<version>_x86_64.qpkg`, `bucketvs_<version>_arm_64.qpkg`). Det är kodsignerat: installera
det från App Center (ett repository som listar det, eller **Installera manuellt** med den nedladdade filen). App
Center kontrollerar signaturen; du behöver inte tillåta appar utan giltig signatur.

Installationen skapar tjänsteanvändaren `bucketvs` (för Forgejo och httpd), länken `/usr/bin/bucketvs` till
installationsmappen, och startar bvsd. Systemloggarna anger datamapp.

### Var datamappen börjar

Vid första starten är datamapp `BucketVS` på den volym som paketet är installerat på, till exempel
`/share/CACHEDEV1_DATA/BucketVS` (QTS) eller `/share/ZFS2_DATA/BucketVS` (QuTS hero). Den kan senare flyttas till en
annan volym från panelen ([Flytta datamappen](#flytta-datamappen)).

Paketet minns sin datamapp i `/etc/config/bucketvs-data-root`, en fil som överlever paketet. Att ta bort paketet lämnar
kvar datamapp och den här filen, så en installation efter en borttagning startar på samma data och samma konton. En start
är aldrig beroende av en mapp som inte finns. När datamappen är borta (borttagen, på en disk som har bytts ut, eller på
en volym som är offline just då) skapar starten `BucketVS` på paketets volym, en ny mapp om inte en mapp med det namnet
redan finns där, och i en ny mapp sätter [första inloggningen](#första-inloggningen) administratörens lösenord. Det
gäller efter en ominstallation och för ett installerat paket, även vid uppstart. Systemloggarna har en varning om det,
och `.prev`-filer behåller den gamla sökvägen: `/etc/config/bucketvs-data-root.prev` och för ett installerat paket även
`etc/data-root.prev` i installationsmappen. Låg den gamla mappen på en volym som bara var offline just då, ta volymen
online, stoppa paketet, kopiera den filen över `etc/data-root` i installationsmappen (till exempel
`/share/CACHEDEV1_DATA/.qpkg/bucketvs/etc/data-root`) och starta paketet: det körs då på den gamla datan igen.

### Öppna panelen från App Center

**Öppna** vid paketet i App Center öppnar panelen på port 9950 (HTTP) eller 9951 (HTTPS). När portarna ändras i
panelen ([Portar](#portar)) meddelar paketet App Center de nya vid nästa start.

### Autostart från en SSH-session

Så länge paketets reglage i App Center är på startar NAS:en paketet vid uppstart. I en SSH-session på NAS:en ställer
du som admin in samma reglage med tjänsteskriptet:

```sh
/etc/init.d/bucketvs.sh disable   # nästa start avvisas, även vid uppstart
/etc/init.d/bucketvs.sh enable    # paketet startar vid uppstart igen
```

Båda kommandona skriver bara reglaget (`Enable` i `/etc/config/qpkg.conf`), skriver ut vad de ställde in och skriver
samma rad till systemloggarna. Ett paket som körs fortsätter att köras efter `disable`, och `enable` startar
ingenting: det gör `stop` och `start`, och `start` vägrar så länge paketet är avstängt. `status` visar om bvsd körs.

## Första inloggningen

Öppna panelen på `https://<NAS-adress>:9951/` eller `http://<NAS-adress>:9950/`. HTTPS-adressen använder först ett
självsignerat certifikat, så webbläsaren varnar tills enheten litar på det; avsnittet [Certifikatet](#certifikatet)
visar hur du jämför dess fingeravtryck.

En ny installation har inget konto. Tills den första administratören har ett lösenord öppnar panelen på en enda skärm,
”Sätt administratörslösenordet”, för kontot `administrator`. Skriv ett lösenord två gånger: minst 10 tecken och högst
72 byte. När du sparar det skapas kontot och du loggas in.

```mermaid
flowchart TD
    start["Paketet startar<br/>utan något konto"] --> screen["Sätt administratörslösenordet<br/>60 minuter, bara lokalt nätverk"]
    screen -->|"sparat"| panel["administrator inloggad"]
    screen -->|"60 minuter har gått"| restart["Starta om paketet i App Center:<br/>ett nytt fönster på 60 minuter"]
    restart --> screen
```

- Skärmen tar emot ett lösenord i 60 minuter efter att paketet startat. Därefter säger den att fönstret för att ställa
  in har stängts; att starta om Bucket & Code Server IDE i App Center öppnar ett nytt fönster på 60 minuter.
- Den tar bara emot ett lösenord från det lokala nätverket: från NAS:en själv, eller från en adress i ett privat
  intervall (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.0.0/16`, `fc00::/7`, `fe80::/10`).
- Medan skärmen är öppen visar QTS systemloggar en informationspost för varje LAN-adress till NAS:en, till exempel:

  ```text
  bucketvs: no administrator yet: open https://192.168.1.20:9951/ within 60 minutes to set the administrator's password
  ```

- Den avvisar en begäran som kom via en proxy (en som har `X-Forwarded-For`, `X-Forwarded-Host`, `X-Forwarded-Proto`,
  `X-Real-IP` eller `Forwarded`), även från en proxy på LAN:et: öppna panelen direkt från en dator i det lokala
  nätverket för att sätta lösenordet.

Från en SSH-session på NAS:en skapar `/usr/bin/bucketvs/bin/bvs user password administrator` kontot när det inte finns
något ännu och skriver ut ett slumpat lösenord; panelen ber sedan om ett eget lösenord vid första inloggningen ([När
en admin är utelåst](#när-en-admin-är-utelåst)).

Efter första inloggningen säger Översikt att bara kärnan körs. Varje moduls ruta säger vad modulen ger och har en
knapp som slår på den, till exempel **Slå på Git**: slå på dem du behöver ([Moduler](#moduler)).

## Arbeta i panelen

Panelen fungerar som en kodredigerare: varje sida öppnas i en flik, och en kommandopalett når sidorna och åtgärderna
via namn.

- **Aktivitetsfältet** (ikonerna till vänster). Varje ikon öppnar sin sida och visar sitt träd i sidofältet:
  modulerna, repositoryn och buckets, appar, paket, miljöer, jobb och säkerhetskopior. En punkt på en ikon markerar en
  modul med problem, ett misslyckat bygge eller en misslyckad säkerhetskopiering. Ett klick på ikonen för sidan som
  visas döljer sidofältet; Ctrl+B gör samma sak.
- **Flikar.** En sida som öppnats med ett enkelklick är en förhandsvisning, i kursiv stil: nästa sida öppnas i dess
  ställe. Redigera sidan eller dubbelklicka på dess flik för att behålla den. Flikarna kommer tillbaka efter en
  omladdning, för varje konto i varje webbläsare. I ett fönster som är minst 1280 pixlar brett visar **Flytta fliken
  till andra sidan** (`Ctrl+\`) två sidor sida vid sida.
- **Objekt och deras menyer.** Ett klick på en rad i sidofältet, en tabellrad eller ett kort öppnar objektet: dess
  sida kommer fram med objektet inom en grön ram, eller med detaljerna öppna. Adressen namnger objektet, så bakåt,
  framåt och en kopierad länk leder tillbaka dit. Ett dubbelklick behåller fliken. Ett högerklick, Skift+F10 eller en
  lång tryckning på en pekskärm öppnar objektets meny: sätten att öppna det (i den här fliken, i en behållen flik, på
  andra sidan, i en ny webbläsarflik), vad dess sida kan göra med det, och kopior av namnet och adressen. En fliks
  meny stänger den, de andra flikarna, flikarna till höger eller alla. Bara ett element märkt ↗ lämnar panelen. Ikonen
  **Administration** öppnar sidan System.
- **Kommandopaletten.** Ctrl+Skift+P (eller Ctrl+K, eller F1) listar de kommandon din roll får köra: öppna en sida,
  bygga eller publicera en app, köra en säkerhetskopiering, starta om en modul, öppna ett skal i en miljö. Ctrl+P går
  till en sida, en app, ett repository, en miljö eller ett paket med några bokstäver ur namnet.
- **Nedre panelen** (Ctrl+J). **Jobb** visar pågående och senaste jobb med förlopp och logg. **Problem** listar vad
  modulerna rapporterar: misslyckade byggen, avstängda mål för säkerhetskopior, moduler med problem, ett certifikat
  som snart går ut, och ELF-inspektörens fynd för appen som visas. **Utdata** följer det jobb du startade sist.
- **Flytta och ändra storlek.** Dra en kant för att ändra storleken på det den gränsar till: sidofältet, den nedre
  panelen, två sidor bredvid varandra eller två delar av en sida bredvid varandra, till exempel en guide och dess
  sammanfattning eller ett projekts fillista och filen. Ett dubbelklick på en kant sätter tillbaka den. En dialogruta
  flyttar du i rubriken och ändrar storlek på i en kant eller i det nedre högra hörnet; ett dubbelklick på rubriken
  sätter tillbaka den i mitten. För att ställa den nedre panelen bredvid sidorna drar du dess rubrikrad till
  redigerarens högra kant eller klickar på knappen bredvid dess ×; dra den till nederkanten, eller klicka på knappen
  igen, för att sätta tillbaka den. En flik kan dras till en annan plats i flikraden eller till andra sidan. Panelen
  sparar varje storlek och plats för ditt konto i den här webbläsaren, och **Återställ layouten** (i kommandopaletten,
  eller under ditt kontos knapp längst ned i aktivitetsfältet) sätter tillbaka allt. Med tangentbordet flyttar
  piltangenterna en markerad kant (med Skift i längre steg, Home sätter tillbaka den), Ctrl+Skift+Vänster och Höger
  flyttar en markerad flik, och en dialogruta har en list överst och ett grepp nere till höger som piltangenterna
  flyttar den och ändrar dess storlek med. På en telefon stannar dialogrutor och den nedre panelen där de är.
- **Statusfältet.** Modulernas tillstånd, pågående jobb, problem, ledigt utrymme på datavolymen, certifikatet, kontot
  som är inloggat, språket (redigeraren tar det vid nästa start, på engelska för svenska och nederländska; Git följer det, om du inte väljer ett annat där), temat (mörkt, ljust, som systemet, djupblått, grafit eller papper: det hör till ditt konto, och redigeraren och Git följer det, om du inte väljer ett annat där) och versionen. Varje post öppnar platsen där du
  kan titta närmare.
- **Tangentbord.** Ctrl+/ eller ? listar kortkommandona. En webbläsarflik behåller Ctrl+W och Ctrl+Tab för sig själv,
  så panelen stänger en flik med Alt+W och byter flik med Alt+PageDown och Alt+PageUp.
- **På en telefon** ligger de första aktiviteterna längst ned, **Mer** öppnar sidofältet med resten, och de öppna
  sidorna är en lista högst upp.

## Konton

Panelen har egna konton. QTS-konton loggar inte in i den.

### Roller

| Roll | Vad den får göra |
|---|---|
| viewer | läser panelen; sidorna Säkerhetskopior, Lagring, Användare och Loggar är för admins. I Forgejo skapar, forkar och importerar den inga repositoryn, skapar ingen organisation och pushar aldrig; läser de SVN-repositoryn och buckets den har rättigheter till och skriver i inget |
| member | läser det en viewer läser, och skriver: pushar till de Git-repositoryn den får skrivåtkomst till, skriver i de SVN-repositoryn och buckets den har läsa och skriva på, och återställer där äldre versioner av filer. I Forgejo skapar, forkar och importerar den inga repositoryn och skapar ingen organisation, och den kan inte pusha till ett repository som ett konto under developer äger eller administrerar, och inte heller, medan CI-modulen är på, till ett repository vars Actions är på. Den får ingen redigerare, inga cron-jobb eller byggen |
| developer | öppnar dessutom redigeraren, läser `bvs use`-raderna för installerade verktygskedjor, skapar, ändrar och kör egna cron-jobb, skapar och bygger appar, publicerar paket i repositoryt (en admin listar dem), kontrollerar kärnmoduler, och skapar Git-repositoryn vars arbetsflöden körs på NAS:en medan CI-modulen är på |
| admin | allt: konton, inställningar, lagring, nätverk, moduler, verktygskedjor, miljöer, alla cron-jobb, aktivera appar, ladda kärnmoduler, lista paket i repositoryt |

Rollen developer är root på NAS:en: dess cron-kommandon körs som root, liksom terminalen i dess redigerare och, medan
CI-modulen är på, arbetsflödena i de repositoryn den får pusha till. Ge den bara till personer som du skulle ge NAS:ens
admin-lösenord. För den som bara skriver i repositoryn räcker rollen member.

Under **Ditt konto** ser var och en sin egen roll och vad den tillåter, med en länk till det här avsnittet. En sida över
någons roll säger vilken roll den kräver, och det som bara en admin ändrar står så angivet där det visas. Nätverk, Git
och CI visar sina inställningar för alla andra som värden, med ”Inte angivet” där ett värde saknas.

Arbetsflöden körs som root på NAS:en, så bvsd håller Actions avstängda i varje Git-repository som en member eller
viewer äger eller som ett sådant konto kan skriva i: att ge ett sådant konto skrivåtkomst till ett repository stänger
av dess Actions inom en minut, och Git-sidan listar de repositoryna för admins. För att använda Actions där tar du
först bort den skrivåtkomsten i Forgejo, eller flyttar ett repository som ett sådant konto äger till en developers
konto.

### Skapa och ändra konton

En admin hanterar konton på sidan Användare.

- Ett nytt konto börjar med rollen viewer. Developer och admin väljs medvetet: rollen developer är root på NAS:en
  (ovan).
- Ett nytt konto börjar utan cron-jobb, även när ett konto med samma namn hade några.
- Ett namn har 2 till 32 tecken: först en liten bokstav, sedan små bokstäver, siffror, `.`, `_` eller `-`. Två av `.`,
  `_`, `-` i rad, eller ett i slutet, avvisas. Det gör också namnen som Forgejo reserverar (`admin`, `api`, `user` med
  flera), `bucketvs` (paketets systemanvändare), `cli` och `system` (bvsd använder båda själv).
- ”Måste välja ett eget lösenord vid första inloggningen” gör att kontot sätter sitt eget lösenord innan det kan göra
  något annat.
- Att inaktivera ett konto avslutar dess sessioner direkt och stoppar dess API-token. Dess data finns kvar. Dess
  [cron-jobb](#schemalagda-jobb) finns också kvar, men körs inte medan det är inaktiverat, och en pågående körning av
  ett av dem stoppas.
- Att ge ett konto rollen member eller viewer gör samma sak med dess cron-jobb: de finns kvar, körs inte medan dess
  roll är under developer, och en pågående körning stoppas.
- En viewer pushar aldrig till Git, inte ens där den fått skrivåtkomst i Forgejo. Ett konto som ska pusha får rollen
  member.
- Att ta bort ett konto tar bort det med dess sessioner och API-token. Dess hemmapp flyttas till
  `trash/home/<namn>-<tid>` i datamapp, där jobbet ”Töm papperskorgen” tar bort den efter 7 dagar, och dess mapp
  `tmp/tmux-<namn>` tas bort. Dess cron-jobb tas bort med sina körningar och loggar.
- Den sista aktiva admin kan inte degraderas, inaktiveras eller tas bort.
- ”Sätt ett nytt lösenord” avslutar kontots sessioner och återkallar dess API-token.

### Lösenord och sessioner

- Ett lösenord har minst 10 tecken och högst 72 byte.
- Att ändra ditt eget lösenord (under Ditt konto) avslutar dina andra sessioner och återkallar dina API-token.
  Sessionen där du ändrade det förblir inloggad.
- En session tar slut 12 timmar efter sin senaste begäran, och i alla händelser 7 dagar efter inloggningen. Ett konto
  har högst 32 sessioner; ytterligare en inloggning avslutar den som använts minst nyligen.
- Sessionskakan är `HttpOnly` och `SameSite=Lax`. Den markeras `Secure` när webbläsaren nådde NAS:en via HTTPS, direkt
  eller genom en [betrodd proxy](#betrodda-proxyservrar).

### Fel lösenord

- Fem misslyckade inloggningar inom 15 minuter från en adress spärrar den adressen i 15 minuter, även med rätt
  lösenord. En IPv6-klient räknas som sitt /64-nät.
- Fem misslyckanden för ett konto från en adress spärrar det kontot från den adressen i 15 minuter.
- Misslyckanden för ett konto från många adresser gör dess nästa inloggningar långsammare: 125 ms efter ett
  misslyckande, fördubblat upp till 2 sekunder. Från det lokala nätverket spärrar de det aldrig.
- Från internet (varje adress utanför det lokala nätverket) låser 20 misslyckade inloggningar för ett konto sedan dess
  senaste lyckade det där, oavsett vilka adresser de kom från; då avvisas även rätt lösenord där. Från det lokala
  nätverket loggar kontot fortfarande in. En administratör låser upp det på sidan Användare (**Lås upp**) eller med
  `bvs user unlock <namn>`, eller ger det ett nytt lösenord. Antalet ställs in på sidan Användare under
  **Inloggningar från internet**; 0 stänger av låsningen.
- Räknarna hålls i minnet, så en omstart av bvsd nollställer dem; en låsning ligger kvar tills den hävs.

Bakom en proxy räknas den adress som proxyn rapporterar, men bara när proxyn är en [betrodd
proxy](#betrodda-proxyservrar). Annars räknas varje klient som proxyns egen adress, och fem fel lösenord från vem som
helst låser ute alla i 15 minuter.

### Tvåfaktorsautentisering

Varje konto slår på den för sig själv under Ditt konto: skanna QR-koden med en autentiseringsapp (eller skriv in
nyckeln) och ange sedan den 6-siffriga kod som appen visar. Därefter frågar inloggningen efter en kod efter
lösenordet.

- Koderna följer RFC 6238: 6 siffror, en ny kod var 30:e sekund. En kod som är 30 sekunder för tidig eller för sen
  godtas. Samma kod godtas aldrig två gånger.
- Om en färsk kod misslyckas går telefonens klocka troligen fel; ställ in den på automatisk tid.
- Att stänga av den kräver kontots lösenord.
- Vid en borttappad telefon stänger en admin av den på sidan Användare. Lösenordet ensamt loggar då in.

### API-token

Skript och CI använder API-token i stället för ett lösenord. Under Ditt konto skapar ”Ny token” en:

- Den ser ut som `bvs_` följt av 40 hexadecimala siffror, och den visas en gång. bvsd sparar bara dess hash.
- Ett skript skickar den som `Authorization: Bearer bvs_...`.
- Dess omfång är `read`, `write` och `admin`, som motsvarar rollerna viewer, developer och admin. En token agerar med
    sitt högsta omfång, aldrig över ägarens nuvarande roll, så att degradera ett konto degraderar också dess token.
  Inget omfång motsvarar member: en member skapar `read`-token.
- Ett nytt lösenord återkallar alla ägarens token. En inaktiverad ägares token slutar fungera.
- En token kan inte ändra lösenord eller tvåfaktorsautentisering, och kan inte skapa eller ta bort token: det kräver en
  inloggad session. En läckt token kan därför inte låsa ute sin ägare.

### När en admin är utelåst

NAS-admin kan återställa vilket konto som helst från en SSH-session på NAS:en. Kommandot `bvs` pratar med bvsd via en
socket som bara root kan öppna (`/usr/bin/bucketvs/var/run/bvsd-cli.sock`, läge 600):

```bash
/usr/bin/bucketvs/bin/bvs user list
/usr/bin/bucketvs/bin/bvs user password administrator
/usr/bin/bucketvs/bin/bvs user totp-reset administrator
/usr/bin/bucketvs/bin/bvs user unlock administrator
```

- `bvs user password <namn>` sätter ett nytt slumpat lösenord på 20 tecken och skriver ut det. Kontot måste välja ett
  eget vid nästa inloggning. Dess sessioner avslutas och dess API-token återkallas. På en ny installation utan konto
  skapar `bvs user password administrator` kontot.
- `bvs user totp-reset <namn>` stänger av tvåfaktorsautentiseringen för kontot.
- `bvs user unlock <namn>` häver kontots låsning efter för många felaktiga lösenord från internet.

Varje begäran på den socketen agerar som den inbyggda admin `cli` och skrivs till `log/audit.log` i datamapp. bvsd
måste köras för de här kommandona.

## Datamappen

Datamapp är den mapp som innehåller allt som paketet sparar. Dess sökväg är den enda raden i
`/usr/bin/bucketvs/etc/data-root`. Sidan Lagring visar den, med volymen den ligger på och det lediga utrymmet där.

bvsd startar bara på en datamapp som är en mapp på en riktig volym. Paketets start kontrollerar det först: en mapp som
saknas, eller en på tmpfs eller ramfs, ger en ny datamapp på installationsvolymen, som [Var datamapp
börjar](#var-datamappen-börjar) beskriver. En volym som är offline lämnar kvar sin monteringspunkt som en tom mapp i
NAS:ens RAM, och inställningar som skrivs där skulle vara borta efter nästa omstart. bvsd själv avvisar en sådan mapp
bara när den startas för hand, och orsaken går då till QTS systemloggar.

### Vad bvsd ger varje process

QTS håller `/tmp` på en liten RAM-disk och `/root` på en RAM-disk som en omstart tömmer. Därför får varje process som
bvsd startar (modulprogram, cron-jobb, installationer) sina tillfälliga filer och sin hemmapp i datamapp:

| Variabel | Värde |
|---|---|
| `HOME` | `<datamapp>/home/<användare>` |
| `TMPDIR` | `<datamapp>/tmp` |
| `XDG_CACHE_HOME`, `XDG_CONFIG_HOME` | `.cache` och `.config` i den hemmappen |
| `npm_config_cache` | `.npm` i den hemmappen |
| `PATH` | `~/.local/bin`, `~/.npm-global/bin`, sedan paketets `bin`, `sbin` och `node/bin`, sedan systemets mappar |
| `SSL_CERT_FILE`, `GIT_SSL_CAINFO`, `CURL_CA_BUNDLE` | paketets CA-paket, `/usr/bin/bucketvs/etc/ssl/cacert.pem` |
| `TZ` | NAS:ens tidszon, så som den är inställd i QTS |
| `SHELL`, `EDITOR` | paketets `bash` och `nano` |
| `LANG`, `LESSCHARSET` | `C.UTF-8` och `utf-8`, så att filnamn med å, ä och ö visas som de är |

### Flytta datamappen

Sidan Lagring flyttar hela datamapp till en annan mapp under `/share`. Välj en delad mapp eller en volym; datan hamnar
i en ny mapp med namnet `BucketVS` där. För att använda en mapp i sig öppnar du en tom mapp med namnet `BucketVS`.
Delade mappar skapas i QTS (Kontrollpanelen, Delade mappar); i en delad mapp eller en volym kan sidan skapa en ny
mapp. Väljaren öppnas där data ligger nu och säger det; öppna därifrån den delade mapp eller volym som den ska flyttas
till.

Sidan kontrollerar målet innan flytten börjar och listar varje skäl till att den avvisar ett:

- sökvägen måste ligga under `/share`, och inte vara `/share` själv;
- inget `:`, `&`, `|` eller kontrolltecken i någon del av sökvägen, inte heller i sökvägen som en länk leder till;
- inte den nuvarande datamapp, inte en mapp i den, inte en mapp som innehåller den;
- en ny mapp, eller en tom;
- ett filsystem som behåller Unix-ägare och -behörigheter (FAT, exFAT och NTFS avvisas: Forgejo och SVN behöver ägare
  och lägen);
- en volym som är monterad med `exec`, `dev` och `suid`, vilket byggmiljöer behöver;
- skrivbar, med ledigt utrymme för datan plus 10 %.

```mermaid
flowchart TD
    check["Kontrollera målet igen<br/>ledigt utrymme: datan + 10 %"] --> stop["Stoppa modulerna<br/>panelen är kvar"]
    stop --> copy["Kopiera med<br/>rsync -aHAX --numeric-ids"]
    copy --> verify["Verifiera kopian<br/>filer, byte, ägare, lägen, tider,<br/>sha256 för upp till 1000 filer"]
    verify --> switch["Byt datamapp<br/>i /usr/bin/bucketvs/etc/data-root"]
    switch --> start["bvsd startar igen på den nya roten<br/>och startar modulerna"]
    start --> old["Den gamla kopian finns kvar, märkt MOVED-TO,<br/>tills du tar bort den"]
    copy -->|misslyckas| failed["Den gamla roten används fortfarande,<br/>modulerna startar igen"]
    verify -->|en skillnad| failed
```

Medan flytten pågår:

- Git, CI, SVN och Bucket samt Redigerare svarar inte. Panelen är kvar och visar förloppet.
- Ingen ny cron-körning startar. En körning som redan pågick fortsätter.
- Att slå på eller av en modul avvisas tills flytten är klar.

Efter bytet stoppar bvsd och startar sig själv igen på den nya roten, så panelen är borta några sekunder.

När flytten misslyckas används den gamla datamapp fortfarande och modulerna startar igen. Jobbets fel säger vad som
gick fel och vad som hände med kopian:

- En full volym, eller en avbrytning, tar bort det som flytten skapade.
- Alla andra fel (kopieringen, kontrollen, skrivning till disk) behåller kopian, märkt med en fil som heter
  `INCOMPLETE`, och listar den på sidan Lagring under ”Kvarlämnade kopior från misslyckade flyttar”.
- Ett stopp av paketet under flytten behåller den gamla roten som datamapp. Vid nästa start rapporterar bvsd den
  ofullbordade flytten i systemloggarna och listar kopian.

### Den gamla kopian och kvarlämnade kopior

Efter en lyckad flytt ligger den gamla datamapp kvar där den var, med en fil som heter `MOVED-TO` i sig. Ingenting
använder den. ”Ta bort den gamla kopian” på sidan Lagring tar bort den, och ”Ta bort den här kopian” tar bort en
kvarlämnad kopia från en misslyckad flytt. Båda borttagningarna håller sig på ett filsystem och följer aldrig en länk.
En mapp som är en monteringspunkt eller en delad mapps egen mapp töms och behålls.

## Nätverk

Sidan Nätverk innehåller portarna, läget för vanlig HTTP, modulernas värdnamn, de betrodda proxyservrarna, den publika
URL:en och certifikatet. När du sparar startas det om som ändringen kräver, och det listas.

### Portar

| Inställning | Standard | Vad den är |
|---|---|---|
| HTTPS | 9951 | panelen och modulerna via TLS |
| HTTP | 9950 | panelen och modulerna via vanlig HTTP |
| Git via SSH | 9952 | Git via SSH |
| SSH-port i klon-URL:er | 0 | porten som visas i SSH-klonadresser; 0 betyder SSH-porten ovan. Ställ in den när en router vidarebefordrar en annan port till NAS:en. |
| SSH-värd i klon-URL:er | tomt | namnet eller adressen som visas i SSH-klonadresser. Tomt betyder Git-värdnamnet, annars värden i den publika URL:en, annars NAS:ens LAN-adress; för ett namn som publiceras via Cloudflare Tunnel, LAN-adressen och porten för Git via SSH. Ställ in den på ett namn som bara finns i DNS eller på routerns adress när routern vidarebefordrar SSH-porten. |

Portarna ligger mellan 1024 och 65535 och skiljer sig från varandra. Modulportarna på 127.0.0.1 (9960 och 9961)
avvisas, liksom porten som httpd eller CI-runnerns server använder när ett annat program har tagit 9960 eller 9961
(meddelandet anger den). När sparandet lämnar nginx på sina gamla portar för att den inte kunde använda en ny, säger
en avisering varför. nginx lyssnar också på IPv6 när NAS:en har det.

### Vanlig HTTP

- ”Servera” (standard): panelen och modulerna svarar även på vanlig HTTP. Behåll detta när en proxy på LAN:et pratar
  vanlig HTTP med port 9950.
- ”Omdirigera till HTTPS”: en begäran på vanlig HTTP får en omdirigering (307) till HTTPS-porten. En begäran från en
  betrodd proxy som säger att dess klient använde HTTPS serveras på vanlig HTTP, så att en sådan proxy inte hamnar i
  en slinga.

Inloggningssidan varnar när den kom via vanlig HTTP: lösenordet går då läsbart över nätverket.

### Certifikatet

Vid första starten skapar bvsd ett självsignerat certifikat (ECDSA P-256) för:

- NAS:ens värdnamn, modulernas värdnamn och `localhost`;
- NAS:ens LAN-adresser och `127.0.0.1`.

Det är giltigt i 825 dagar, det mesta som Apple-enheter godtar, även för ett certifikat som betrotts för hand. bvsd
kontrollerar det vid start och en gång om dagen, och skapar ett nytt när 30 dagar eller färre återstår, när
uppsättningen namn ändras, eller när dess nyckel inte stämmer. Ett nytt skickar en [avisering](#aviseringar). Sidan
Nätverk visar dess namn, dess giltighet och dess SHA-256-fingeravtryck: jämför fingeravtrycket innan en enhet litar på
det.

”Lägg till ett eget certifikat” tar en certifikatkedja och dess privata nyckel i PEM-form:

- servercertifikatet först, sedan mellanliggande certifikat;
- en nyckel utan lösenfras (nginx startar utan tillsyn);
- nyckeln måste höra till det första certifikatet, varje certifikat måste vara signerat av nästa, inget får ha gått
  ut, och det första måste ange sina värdar som subject alternative names.

Paret sparas i `etc/tls/` i datamapp med läge 600. När ett uppladdat certifikat går ut eller slutar klara de här
kontrollerna serverar nginx det självsignerade i stället och en avisering säger varför. Ett uppladdat certifikat med
30 dagar eller färre kvar skickar också en avisering. ”Nytt självsignerat certifikat” skapar ett nytt självsignerat
par och byter tillbaka till det.

Klienter som kommer via en proxy ser proxyns certifikat, inte det här.

**Ladda ned certifikatet** på sidan Nätverk sparar certifikatet som panelen serverar, utan dess nyckel, som
`<namn>.crt`. Lägg till det bland en enhets betrodda certifikat så litar enhetens webbläsare på panelen; redigerarens
tilläggsvyer behöver det ([Tillägg](#tillägg)). Ett nytt självsignerat certifikat måste man lita på igen.

### Betrodda proxyservrar

En lista över IP-adresser eller CIDR-intervall, till exempel `192.168.1.5`, adressen till proxyn framför NAS:en. Bara
för en begäran vars TCP-anslutning kommer från en av dem tar nginx:

- klientens adress från `X-Forwarded-For`;
- schemat som klienten använde från `X-Forwarded-Proto` (bara `http` eller `https` räknas).

En begäran från någon annan adress räknas som att den kom direkt från sin klient, och nginx ersätter dess
`X-Forwarded-*`-huvuden med egna värden. Ett intervall gör varje värd i det betrodd: var och en av dem kan då ange
klientadressen och schemat, så ange proxyns egen adress. Ett intervall med alla adresser (`0.0.0.0/0`, `::/0`)
avvisas.

### Publik URL

Bara adressen, till exempel `https://git.example.com`, utan sökväg. Modulavsnitten säger vilka länkar som börjar med
den.

## Bakom en omvänd proxy (Plesk)

Den vanliga uppsättningen lägger TLS på en proxy med ett publikt certifikat och låter den prata vanlig HTTP med port
9950 på LAN:et. Exemplen nedan använder `bvs.example.com` som publikt namn, `192.168.1.20` för NAS:en och
`192.168.1.5` för Plesk-servern; sätt in dina egna i stället.

```mermaid
flowchart LR
    client["Webbläsare, git, WebDAV-klient"] -->|"HTTPS 443"| plesk["Plesks nginx<br/>bvs.example.com<br/>publikt certifikat"]
    plesk -->|"HTTP 9950<br/>Host, X-Forwarded-For,<br/>X-Forwarded-Proto: https,<br/>Upgrade för WebSocket"| nas["nginx på NAS:en<br/>192.168.1.20"]
    nas --> panel["/ panel, /api/ bvsd"]
    nas --> mods["/git/, /svn/, /bucket/, /ide/"]
    sshc["git via SSH"] -->|"TCP 9952, inte via proxyn"| nas
```

### På NAS:en

1. På sidan Nätverk lägger du till Plesk-serverns adress (så som NAS:en ser den) bland de betrodda proxyservrarna.
2. Vanlig HTTP kan stå kvar på ”Servera”. ”Omdirigera till HTTPS” fungerar också när Plesk-servern är en betrodd
   proxy.

### I Plesk

Lägg in de här direktiven i domänens inställningar för Apache och nginx, i fältet ”Ytterligare nginx-direktiv” (i det
engelska gränssnittet ”Additional nginx directives”):

```nginx
location ~ ^/ {
    proxy_pass http://192.168.1.20:9950;
    proxy_http_version 1.1;

    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # WebSocket: redigeraren och dess terminal
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;

    # stora push och uppladdningar: ingen storleksgräns, strömmat, en timmes tystnad tillåten
    client_max_body_size 0;
    proxy_request_buffering off;
    proxy_buffering off;
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}
```

`location ~ ^/` är en location med reguljärt uttryck. nginx föredrar ett matchande reguljärt uttryck framför en vanlig
`location /` (Plesk skriver en egen), så det här blocket betjänar varje sökväg på webbplatsen, och `proxy_pass` utan
sökväg skickar vidare begärans sökväg oförändrad. Stäng av ”Servera statiska filer direkt via nginx” på samma
inställningssida: när det är på svarar Plesk på begäranden efter `.js`-, `.css`- och bildfiler från domänens egen
mapp, och panelen laddas inte.

Slå på den permanenta, SEO-säkra 301-omdirigeringen från HTTP till HTTPS i domänens värdinställningar (i det engelska
gränssnittet ”Permanent SEO-safe 301 redirect from HTTP to HTTPS”). De ytterligare nginx-direktiven gäller också
domänens webbplats på vanlig HTTP på port 80; utan omdirigeringen svarar webbplatsen även där, och lösenord går
okrypterade över internet.

Varför varje rad spelar roll:

| Direktiv | Vad som går sönder utan det |
|---|---|
| `Host $http_host` | nginx på NAS:en väljer serverblock efter `Host`, så ett modulvärdnamn matchar aldrig. bvsd jämför sidans `Origin` med `Host`, port inräknad, så varje ändring i panelen misslyckas med `403 csrf`; `$host` skulle tappa en annan publik port än 443 och misslyckas på samma sätt. |
| `X-Forwarded-For` | varje klient räknas som Plesk-servern: en persons fem fel lösenord låser ute alla i 15 minuter |
| `X-Forwarded-Proto $scheme` | sessionskakan markeras inte `Secure`, och i läget ”Omdirigera till HTTPS” skickas varje begäran till port 9951 på det publika namnet |
| `Upgrade`, `Connection` | redigerarens sida öppnas men redigeraren och dess terminal ansluter aldrig |
| `client_max_body_size 0`, `proxy_request_buffering off`, tidsgränserna | proxyns egen storleksgräns och tidsgränser gäller för stora push och uppladdningar |

`X-Forwarded-For` och `X-Forwarded-Proto` räknas bara när Plesk-servern finns bland de betrodda proxyservrarna. När
den inte gör det ignorerar nginx på NAS:en dem.

### Git via SSH

En HTTP-proxy för inte vidare SSH. Git via SSH går direkt till port 9952 på NAS:en, eller genom en vidarebefordran av
TCP-porten i routern. ”SSH-port i klon-URL:er” på sidan Nätverk anger porten som klonadresserna visar, och
”SSH-värd i klon-URL:er” namnet eller adressen, när det publika namnet bara når proxyn.

### Kontrollera uppsättningen

- Panelen öppnas på `https://bvs.example.com/`, och att logga in och spara en inställning fungerar.
- Webbläsarens utvecklarverktyg visar sessionskakan `bvs_session` med flaggan `Secure`.
- Sidan Loggar visar `nginx-access`: det första fältet på varje rad är klientens egen adress, inte Plesk-serverns.

## Värdnamn för modulerna

En modul kan ha ett eget värdnamn (sidan Nätverk, Värdnamn). nginx serverar då den modulen ensam i roten av namnet.
Namnet måste peka på NAS:en, eller på proxyn framför den. På en proxy behöver varje värdnamn en egen webbplats, med
samma direktiv som ovan.

| Modul | I roten av sitt värdnamn | Också där |
|---|---|---|
| Git | Forgejo | `/git/` på varje annat namn svarar 302 till Git-värdnamnet, med samma sökväg, fråga och port |
| Redigerare | code-server | panelens inloggningssida och `/api/`, så att en användare kan logga in på det namnet |
| SVN och Bucket | httpd | repositoryn ligger kvar på `/svn/<namn>` och buckets på `/bucket/<namn>` |

En modul som är av svarar `503` med en mening som säger det, på sina sökvägar och på sitt värdnamn.

### En inloggning för alla värdnamn

Sessionskakan hör till det namn den sattes på, om inte inställningen `network.cookie_domain` anger en överordnad domän
till alla modulvärdnamn. Med `example.com` når en inloggning på `bvs.example.com` också `git.example.com` och
`ide.example.com`. bvsd avvisar ett publikt suffix (`com`, `com.pl`, `co.uk`, `myqnapcloud.com`), en domän som inte är
överordnad alla modulvärdnamn, och varje domän så länge inget modulvärdnamn är inställt. Varje webbplats under den
domänen får kakan, så ange den snävaste gemensamma överordnade domänen.

Sidan Nätverk visar inte den här inställningen. NAS-admin ställer in den via CLI-socketen med paketets `curl`:

```bash
/usr/bin/bucketvs/bin/curl --unix-socket /usr/bin/bucketvs/var/run/bvsd-cli.sock \
  -X PUT -H 'Content-Type: application/json' \
  -d '{"network":{"cookie_domain":"example.com"}}' \
  http://bvsd/api/v1/settings
```

Ett tomt värde (`""`) håller åter kakan på varje namn för sig.

## Publicera på internet (Cloudflare Tunnel)

Sidan **Publicering** (Administration, bara admins) lägger ut paketet på internet under namn i en domän vars DNS finns
hos Cloudflare. `cloudflared`, som paketet levererar, ansluter från NAS:en ut till Cloudflare: ingen port i routern
öppnas, och Cloudflare håller certifikaten för namnen. Varje begäran går genom paketets nginx: panelen och
dess API kräver inloggning, och utan konto öppnas bara det du har gjort offentligt (offentliga förråd, deras
webbvy, paketförrådet).

Det finns två typer av namn, högst ett av varje:

| Typ | Exempel | Vad det serverar |
|---|---|---|
| Huvudvärdnamn | `code.example.com` | panelen och dess API, Forgejo på `/git/`, webbvyn på `/svn-web/` och `/bucket-web/`, paketrepositoryt på `/repo/` (bara läsning) och handboken. `/svn/` och `/bucket/` svarar 404 där, och `/ide/` också tills du publicerar redigeraren (nedan) |
| Värdnamn för paket | `qpkg.example.com` | bara GET och HEAD av `/repo/`, för App Center på andra NAS-enheter; allt annat svarar 404 |

### Vad token behöver

Skapa en API-token på dash.cloudflare.com (My Profile, API Tokens) med de här behörigheterna, för namnens zon:

- Account, Cloudflare Tunnel, Edit
- Zone, DNS, Edit
- Zone, Cache Rules, Edit
- Zone, Cache Purge, Purge

Paketet förvarar token på NAS:en i en fil som bara root läser, och visar den aldrig igen.

Om token har Client IP Address Filtering, lägg in båda NAS:ens publika adresser där, IPv4 och IPv6: NAS:en anropar
Cloudflare över IPv6 när den har en IPv6-adress. Annars vägrar sidan Publicering med `token_ip_filter` och anger
adressen som Cloudflare såg.

### Publicera

Skriv namnen och token och sedan **Publicera**. Paketet kontrollerar först allt hos Cloudflare och ändrar inget där
när en kontroll misslyckas; meddelandet säger vad du ska rätta:

- en behörighet som token saknar, med dess namn;
- ett namn i en zon som token inte ser;
- en DNS-post som namnet redan har (dess typ och vart den pekar): ta bort den hos Cloudflare eller välj ett annat
  namn;
- ett huvudvärdnamn medan **Publik bläddring** (sidan Git) är av, eftersom dess besökare inte har något konto;
- namn i zoner hos två Cloudflare-konton.

Sedan skapar det tunneln (med namnet `bucketvs-<NAS-namn>` om du inte anger ett namn; en tunnel med det namnet som
Cloudflare har kvar tas över), låter varje namn peka på den med en proxad CNAME-post, lägger till cachereglerna och
startar cloudflared. **Publicera igen** med samma värden ändrar ingenting. Ställ in den publika URL:en (Nätverk) på
huvudvärdnamnets `https://`-adress, så att Forgejos länkar och HTTPS-klonadresser anger den; sidan påminner dig
medan de skiljer sig.

Git via SSH går inte genom tunneln: Cloudflare för bara HTTP till ett publicerat namn. SSH-klonadressen är därför
NAS:ens LAN-adress och dess port för Git via SSH (9952), i panelen och i Forgejos egen klonruta, och sidan Git och
Översikt säger ”Kloning via SSH fungerar i det lokala nätverket; från internet klonar du via HTTPS.” För SSH från
internet vidarebefordrar du SSH-porten i routern och ställer in **SSH-värd i klon-URL:er** (Nätverk) på routerns
publika adress eller på ett namn som bara finns i DNS och pekar på den, med **SSH-port i klon-URL:er** när routern
använder en annan port.

Huvudvärdnamnet svarar 404 på `/ide/` tills en administratör slår på reglaget **Publicera redigeraren på
huvudvärdnamnet** på sidan **Publicering**. Redigerarens terminal är ett root-skal på NAS:en, och den som loggar in
där från internet som utvecklare eller administratör får det, så slå först på tvåfaktorsautentisering för de kontona. Med
reglaget på går redigeraren genom samma inloggning som på LAN, dess portproxy (`/ide/proxy/<port>/`) förblir av där
och Cloudflare cachar aldrig dess sidor. Så länge det är på visar Översikt **Redigerare på internet**.

Så länge CI-modulen är på körs ett arbetsflöde som pushas till valfritt förråd i denna Forgejo som root på NAS:en
genom NAS:ens egen runner, oavsett om det pushades från internet eller från LAN: samma makt som redigerarens terminal.
Sidan **Publicering** säger det under **Vad internet når**. Ge push-åtkomst bara till personer som du skulle ge NAS:ens
administratörslösenord.

### Cachen

Med **Cacheförval** på behåller Cloudflare paket (`*.qpkg`) i ett år, ikoner i en dag, `repo.xml` i 5 minuter och
panelens filer i ett år; API:et, Forgejos sidor, inloggningssidorna och webbvyn behålls aldrig. En publicering i
paketrepositoryt tar direkt bort `repo.xml` (och en ändrad ikon eller en borttagen versions filer) ur Cloudflares
cache. Paketet lägger till sina egna regler sist bland zonens cacheregler och ändrar aldrig de andra.

### Inloggning från internet

Det första lösenordet kan aldrig sättas via ett publicerat namn: den första inställningen tar bara emot en lokal
klient. Fel lösenord räknas per internetklient, som på LAN:et. Ett lösenord som skickas med git till Forgejo räknas
också; en åtkomsttoken från Forgejo fungerar som alltid. Cloudflare tar emot begäranden upp till 100 MB, så en större
push eller uppladdning går via LAN-adressen.

### Stoppa och ta bort

**Stoppa** avslutar cloudflared; namnen visar då Cloudflares egen felsida, och ingenting ändras hos Cloudflare. **Ta
bort från Cloudflare** tar bort DNS-posterna, cachereglerna och tunneln som paketet skapade (en övertagen tunnel
ligger kvar) och glömmer token. Medan namn är publicerade visar Översikt en etikett **Internet** med tunnelns
tillstånd.

## Moduler

Översikt visar varje modul med dess processer, minne och CPU, och slår på och av den (bara admin). En modul som är av
säger vad den ger; en admin slår på den med dess knapp (**Slå på Git**, **Slå på Redigerare** och så vidare) på dess
ruta, på dess egen sida eller, för modulen Redigerare, i fliken Redigerare.

- Att slå på en modul kör ett jobb: modulen förbereder sig, reglaget sparas, och dess processer startar. Jobbet väntar
  upp till 30 sekunder på dem.
- CI behöver Git: Git kan inte stängas av medan CI är på.
  Medan Git är av heter CI:s knapp **Slå på Git och CI** och slår på Git först.
- En modul som är av kör ingen process och använder inget minne.
- Kärnan är alltid på.

| Tillstånd | Betydelse |
|---|---|
| körs | varje process i modulen körs |
| startar | en process startade för mindre än en sekund sedan |
| försämrad | en process väntar på att startas om, modulens filer kunde inte skrivas, eller dess hälsokontroll misslyckas |
| startar om i en slinga | en process avslutades 5 gånger inom 10 minuter; bvsd startar den igen var 15:e minut, och en avisering gick ut |
| stoppad | modulens processer körs inte (en flytt av datan stoppade dem, eller de kunde inte starta) |
| av | modulen är av |

En process som avslutas startas igen efter 1 sekund, sedan 2, 4 och så vidare upp till 60 sekunder. Efter 10 minuters
körning börjar väntan om från 1 sekund. En process som startar om i en slinga startar igen direkt när dess modul slås
av och på.

## Git

Git-modulen kör Forgejo, ett webbgränssnitt för git-repositoryn med ärenden, pull requests, utgåvor, wikis, LFS,
speglar och webhooks. En admin slår på den med **Slå på Git** i Översikt eller på Git-sidan. Jobbet förbereder
Forgejos mappar och databas i `<data>/forgejo`, lägger till varje panelkonto i Forgejo, och startar det. Forgejo
öppnas sedan på `/git/` på panelens adress, eller på `/` på Git-värdnamnet när ett sådant är inställt (se [Värdnamn
för modulerna](#värdnamn-för-modulerna)).

**Nytt repository** på Git-sidan, och på Översikts Git-ruta så länge det inte finns något, öppnar Forgejos formulär
för ett repository.
Panelen erbjuder den, och **Migrera eller spegla ett repository**, från rollen developer och uppåt: Forgejo låter
inte en viewer eller en member skapa något repository.

### Repositoryn och konton

- **En inloggning.** Forgejo har ingen egen inloggning: `/git/user/login` går till panelens inloggning, med
  autentiseringskoden när kontot har en, och tillbaka till Forgejo efteråt.
- **Kontona kommer från panelen.** Varje panelkonto har ett Forgejo-konto med samma namn och samma lösenord. Rollen
  `admin` är webbplatsadministratör i Forgejo. Ett inaktiverat konto, eller ett som först måste byta lösenord, kan
  inte heller logga in i Forgejo. En ändring i panelen når Forgejo inom några sekunder. Sidorna Användare och Git
  visar varje kontos tillstånd i Forgejo, och **Synkronisera alla konton nu** på sidan Git kör synkroniseringen igen.
- **Att ta bort ett konto** i panelen pensionerar dess Forgejo-konto: det kan inte längre logga in, och dess token och
  SSH-nycklar tas bort, men dess repositoryn finns kvar. Namnet kan inte ges till ett nytt panelkonto förrän en admin
  byter namn på eller tar bort det gamla Forgejo-kontot i Forgejos webbplatsadministration (**Användarkonton**).
- **Ett konto som skapats i Forgejo självt** ändras aldrig av panelen. Ett panelkonto med samma namn visar orsaken och
  väntar tills ett av dem byter namn.
- **Tvåfaktorsautentisering och git.** Forgejo tar inte emot något lösenord för ett konto med tvåfaktorsautentisering påslagen.
  git via HTTP eller HTTPS behöver då en åtkomsttoken från Forgejo (Forgejos **Inställningar**, **Applikationer**) i
  stället för lösenordet. SSH-nycklar fungerar som förut.
- **Repositoryn** skapas, importeras och speglas på Forgejos egna sidor. Import från adresser på LAN:et är tillåten
  som standard (inställning: `git.allow_local_networks`), eftersom en NAS oftast speglar från sitt eget nät.

### Klona via HTTPS och SSH

På sidan Git skriver **Klona ett repository** båda kommandona för en ägare och ett repository:

| Sätt | Adress | Inloggning |
|---|---|---|
| HTTPS (eller HTTP) | `https://<NAS-adress>:9951/git/<ägare>/<repo>.git` | panelens användarnamn och lösenord, eller en åtkomsttoken |
| SSH | `ssh://git@<NAS-adress>:9952/<ägare>/<repo>.git` | en SSH-nyckel som lagts till i Forgejos **Inställningar**, **SSH / GPG-nycklar** |

- Med en publik URL (bakom en proxy, [Publik URL](#publik-url)) använder HTTPS-adressen den; med ett Git-värdnamn är
  sökvägen `/<ägare>/<repo>.git` på det namnet.
- SSH-porten är `network.ssh_port` (9952), eller `network.public_ssh_port` när en router vidarebefordrar en annan port
  till den. Proxyn för inte vidare SSH: vidarebefordra porten i routern (se [Git via SSH](#git-via-ssh)).
- Ett namn som publiceras via Cloudflare Tunnel bär inte SSH, så SSH-klonadressen anger då NAS:ens LAN-adress, om inte
  `network.public_ssh_host` (Nätverk, ”SSH-värd i klon-URL:er”) anger ett namn som bara finns i DNS eller routerns
  adress.
- Stora push kapas inte: nginx sätter ingen storleksgräns för kroppen på `/git/`.

### Visa repositoryn för personer utan konto

**Publik bläddring** på sidan Git låter alla som når Forgejo läsa dess publika repositoryn utan konto. I Forgejo är
varje repository publikt eller privat (dess **Inställningar**, **Synlighet**). Med reglaget på kan en besökare utan
konto:

- öppna ett publikt repository, dess mappar och filer, och ladda ner en fil som den är;
- läsa historiken, öppna en commit med dess diff (även som `.diff`- eller `.patch`-fil) och jämföra två commits;
- se dess utgåvor, ladda ner ett arkiv, och klona det via HTTP
  (`git clone https://<NAS-adress>:9951/git/<ägare>/<repo>.git`);
- hitta publika repositoryn under **Utforska** och på ägarens profil.

Ett privat repository förblir dolt: dess adress svarar ”hittades inte”. Medan reglaget är på listar Forgejo inte
heller några konton (fliken **Användare** under Utforska och användarsökningen är avstängda, även för inloggade
användare), så en besökare kan inte samla in kontonamnen. Push, ärenden, pull requests och inställningar kräver
fortfarande ett konto. Med reglaget av ber varje sida besökaren att logga in först.

För att dela ett repository gör du det publikt i Forgejo, slår på **Publik bläddring** och skickar adressen. På ett
Git-värdnamn är adressen `https://<Git-värdnamn>/<ägare>/<repo>`.

### Nytt projekt

**Nytt projekt** är en sida som tar ett projekt steg för steg från ingenting till en byggd och publicerad första
version. Den öppnas i en egen flik från kommandopaletten (Ctrl+Skift+P, **Nytt projekt**), överst i Redigerarens
sidofält, i Git-sidofältets huvud, på Git-sidan och på sidan Projekt; ett exempel under **Redigerarprojekt** på sidan
Exempel har **Nytt projekt från det**. Den kräver rollen utvecklare, modulerna Git och Redigerare och ditt konto i
Forgejo (Git-sidan visar dess synkronisering). Så länge Git eller Redigerare är avstängd säger sidan det ovanför
stegen, och en admin slår på dem där med en knapp.

1. **Mall.** Mallarna är grupperade: Program (C, C++ med CMake, Go, Rust, Node, Python, Java), Paket för QTS (ett
   QPKG-paket, en App Builder-app, ett paket från källkod), Kärna (en kärnmodul, USB-seriedrivrutinen ch341),
   Webbplatser (en statisk webbplats: sidor i `src/`, en Makefile som bygger `public/`, en länkkontroll som `make
   test`) och Exempel. Varje kort säger vad ett bygge gör och markerar vad denna NAS ännu saknar (QDK, en byggmiljö,
   en modul som är av), med en länk till sidan som lägger till det.
2. **Namn och synlighet.** Namnet blir repositoryts och mappen `projects/<namn>`; sidan kontrollerar det medan du
   skriver. Sedan ägaren (ditt konto, eller en organisation där Forgejo låter dig skapa repositoryn), privat eller
   publikt, och en beskrivning om du vill. För en App Builder-app förinställningen den börjar från och målet.
3. **Tjänst**, för ett QPKG-paket och ett paket från källkod: hur paketet startar och stoppar, byggt av block. Välj en
   förinställning (**Kommandoradsverktyg** länkar programmet till `/usr/bin`; **Bakgrundstjänst** lägger till ett
   konto, en datamapp på volymen, programmet startat som kontot, en väntan på dess port och ett stopp med tidsgräns;
   **Webbapp** lägger till App Centers knapp Öppna; **Tom** har bara verben) och ändra sedan dess block. Varje blocks
   kort visar raderna det skriver i skriptet medan du skriver, och ett avvisat värde markeras under sitt fält. Start
   slår aldrig på App Centers Enable, och stopp rör det aldrig. Projektvyn ändrar blocken senare.
4. **Bygge.** Miljön som projektet byggs i, sparad för projektet (projektvyn ändrar den senare), eller ingen, och då
   väljer bvsd en vid varje bygge. Steget föreslår först den miljö som bvsd själv skulle välja och som `bvs qbuild`
   och CI bygger i: Ubuntu 24.04 builder, annars Debian 12 builder, annars en annan Debian- eller Ubuntu-miljö. När
   mallens Makefile ger varje app dess miljö på en ENV-rad säger steget det och frågar inte efter någon, och projektet
   sparar ingen. För ett paket från källkod säger steget också att källans adress och sha256 i startreceptet är
   tillfälliga: det första bygget misslyckas tills receptet anger programmets riktiga källa och den filens sha256.
   Sidan visar arbetsflödet som CI kör vid varje push. **Bygg direkt efter skapandet** är på tills du slår av det;
   för ett paket från källkod är det först av, och du kan slå på det. Utan en Debian- eller Ubuntu-miljö för NAS:en
   säger steget det: en admin skapar byggmiljön där med **Skapa den här miljön**, och sedan erbjuder steget den; slå
   annars av **Bygg direkt efter skapandet** och bygg projektet senare.
5. **Publicering**, för ett QPKG-paket, en App Builder-app eller en webbplats: **Testdriftsättning på denna NAS** (admin,
   endast signerade paket; för en app **Aktivera på denna NAS**), **Publicera i denna NAS:s App Center-förråd** och
   **Publicera på min webbserver** (admin) till ett av [webbmålen](#din-egen-webbserver-webbmål); **Lägg till ett mål**
   sparar ett nytt där. Vart och ett är valfritt. Valet att publicera blir också projektets reglage **Publicera i App
   Center-förrådet** (projektvyn, Inställningar): så länge det är på publicerar projektets CI där vid varje körning.
6. **Granskning** listar alla svar och stegen som kommer att köras. **Skapa projekt** skickar dem.
7. **Förlopp** följer varje stegs jobb: repositoryt och dess första commit, det första bygget, sedan
   testdriftsättningen, publiceringen i App Center och på webben, ett efter ett. En rad visar sitt tillstånd och slutet
   av sin logg; ett klick visar loggen. Ett misslyckat steg säger varför och erbjuder **Försök igen**, och stegen efter
   väntar. I slutet **Öppna projektet**, **Öppna i redigeraren** och **Öppna i Forgejo**. Att ladda om sidan eller gå
   tillbaka till dess flik läser jobben igen och skickar inget steg två gånger. Lämnar du sidan stoppas kedjan;
   projektvyn har samma steg.

När bvsd vägrar projektet (ett namn som en mapp, en app eller ett repository redan har, en ägare där du inte får
skapa), går sidan tillbaka till steget med det svaret, visar skälet under fältet och behåller alla andra svar. En
modul som är av (en admin slår på den från sidan), inget Forgejo-konto och ingen Debian- eller Ubuntu-miljö för en App
Builder-app förklaras i Granskning.

Vad det första jobbet gör:

- Det skapar repositoryt som du, privat om du inte valde publikt.
- Det skapar mappen `projects/<namn>` i datamappen med den första commiten: varje fil i mallen och arbetsflödet
  `.forgejo/workflows/build.yml`, på `main`. Commiten är din (ditt namn och din adress står som författare i mappen),
  och mallens skript är körbara i den. Det pushar commiten som du. `origin` är repositoryts HTTPS-adress, så din nästa
  push går dit. Commiten innehåller också [skillen för AI-assistenter](#koda-med-en-ai-assistent),
  `.claude/skills/qnap-dev/` och `AGENTS.md`. Mappen ligger i redigerarens delade mapp: varje utvecklares redigerare
  öppnar `projects/`, oavsett om repositoryt är privat eller publikt.
- Det sparar den valda miljön för projektet, utom när mallens Makefile ger varje app dess miljö. För en App Builder-app
  skapar det appen med projektets namn och förinställningens recept och knyter den till projektet, så att appen också
  kan bygga recept som du lägger i projektets mapp `recipes/`. Det sparar också ditt publiceringsval som projektets
  reglage Publicera i App Center-förrådet, innan arbetsflödets första körning läser det.

Arbetsflödet körs på NAS:ens runner vid varje push när CI-modulen är på, i miljön som arbetsflödet nämner.
QPKG-arbetsflödet publicerar paketet i [paketrepository](#paketrepository), som bara tar kodsignerade paket. Om den
första commiten eller dess push misslyckas efter att repositoryt skapats tar jobbet bort mappen, tar bort repositoryt
igen och säger varför. Så länge projektets reglage **Publicera i App Center-förrådet** är av skriver `bvs repo publish`
i arbetsflödet ett meddelande i stället för att publicera, och körningen fortsätter.

### Projektvyn

Varje mapp i `projects/` i datamappen har en egen sida: ett projekt från guiden, en kopia av ett exempel under
Redigerarprojekt eller ett repository som du klonat dit. Den öppnas från grenen **Projekt** i Redigerarens sidofält,
från sidan **Projekt**, med **Öppna projektet** i slutet av Nytt projekt och från kommandopaletten
(**Öppna projektet …**, eller Ctrl+P och dess namn). Den kräver rollen utvecklare. Ett projekts meny på sidan Projekt
har också Bygg, Bygg om, Publicera och publiceringen på webbmålen. Samma meny slår på eller av CI:s publicering i
App Center.

Sidan läser mappen och ändrar inget i den på egen hand. Projektets typ följer av dess filer: en App Builder-app med
mappens namn, en `qpkg.cfg` överst (ett QPKG-paket), en `Makefile` överst, eller inget av dem, när projektets
CI-arbetsflöde bygger det. När en App Builder-app har mappens namn behåller ett projekt med en `qpkg.cfg` överst, eller
med en Makefile och en `qpkg.cfg` i `qpkg/`, sitt eget bygge, och Testdriftsättning och Publicera tar fortfarande dess
QPKG.

Remsan överst innehåller stegen. Ett steg som inte kan köras behåller sin knapp, avstängd, och säger varför bredvid och
under remsan. Ett steg som projektet inte alls kan ta försvinner från remsan, och en mening under den säger vad
projektet gör och vart byggets resultat tar vägen: projektets mapp för ett program, sidan Kärnor för en kärnmodul, varje
apps sida för en Makefile som bara bygger App Builder-appar.

- **Bygg** körs som ett jobb i den nedre panelen. Ett QPKG-paket byggs med QDK:s `qbuild`, ett Makefile-projekt med
  `make`, båda i projektets byggmiljö. Loggen nämner varje `.qpkg` som bygget skrev till `build/` och om den har en
  kodsignatur. En App Builder-app byggs som på sin egen sida. När en Makefiles standardmål bara kör rader `./bvsapp.sh
  create` och `./bvsapp.sh build` gör Bygg samma sak genom App Builder: det skapar varje app från en `create`-rad som
  inte finns ännu och bygger sedan apparna en i taget. En `create`-rad är `./bvsapp.sh create NAMN RECEPTFIL [ENV]
  [LINK] [TARGET] [OTHERS]`. En sådan Makefile nämner sitt standardmål och målets förutsättningar i `.PHONY` och
  innehåller bara enkla tilldelningar, varje variabel satt en gång, och enkla regler; en med något annat (ett villkor,
  en include) byggs med make. TARGET är `native`, `aarch64` eller `armv7`, så ett Bygg kan göra en app för den här
  NAS:en och en för ARM 64-bit. OTHERS säger vad en statisk app gör med recept som inte kan länkas statiskt (`refuse`
  eller `bundle`). En app som skapas så tar också projektets egna recept från `recipes/`, utom när mappens namn inte är
  ett projektnamn (till exempel ett namn med mellanslag). När en app med det namnet redan finns med ett annat mål, eller
  med ett annat projekt medan mappen har egna recept, förblir Bygg avstängd och säger hur det åtgärdas. Före det första
  bygget nämner steget apparna som det bygger. Ett Makefile-projekt med sitt paket i `qpkg/` gör paketfilen med `make
  qpkg` i redigerarens terminal; tills den finns säger Testdriftsättning, Publicera och Publicera på webben ”Behöver en
  paketfil”.
- **Bygg om** bygger från början: `make clean`, sedan `make`; för ett QPKG-paket försvinner först de gamla
  `.qpkg`-filerna i `build/`. En Makefile utan målet `clean` kan inte bygga om, och sidan säger det. En App Builder-app
  har ingen Bygg om, och inte heller en Makefile som bara skapar och bygger App Builder-appar.
- **Exportera som QPKG** (admin) finns för en App Builder-app, som på appens sida. Publicera väntar då på en export, som
  på appens sida, och **Öppna appen** i sidhuvudet öppnar den sidan.
- **Testdriftsättning** är för admins. Den installerar den nyaste `.qpkg` på denna NAS med `qpkg_cli`, som App Center
  installerar en fil, och jobbet väntar tills App Center bekräftar det. Paketet förblir installerat tills du tar bort
  det i App Center. Ett paket utan kodsignatur vägras: testdriftsättningen installerar bara signerade paket och hoppar
  aldrig över App Centers signaturkontroll (i själva App Center kan ägaren av en NAS tillåta appar utan signatur; den
  här sidan gör det inte). Signera det med ett certifikat som filer (fall 1 i [Kodsignera ett
  QPKG](#kodsignera-ett-qpkg)). Paketet för Bucket & Code Server IDE självt vägras, eftersom installationen skulle
  ersätta det körande paketet. För en App Builder-app aktiverar testdriftsättningen dess bygge på denna NAS.
- **Publicera** lägger den nyaste `.qpkg` i [paketrepository](#paketrepository) med dess regler: en admins publicering
  blir den listade versionen, en utvecklares väntar på en admin, och ett paket utan signatur vägras om inte förrådet tar
  osignerade paket. En rad under den säger om projektets CI också publicerar i App Center-förrådet; den här knappen
  publicerar i båda fallen.
- **Publicera på webben** (admin) kopierar den nyaste `.qpkg`, eller webbplatsmappen `public/` (annars `dist/`), till
  ett [webbmål](#din-egen-webbserver-webbmål) och läser tillbaka den via målets publika adress. För en webbplats som
  guiden skapade väntar steget på det första bygget, som skriver `public/`.

Ett Makefile-projekt väljer ett mål bredvid **Bygg** (makes standardmål, det första, om du inte väljer ett annat); ett
CMake-projekt byggs, eller byggs och kör sina tester. Ett kärnmodulprojekt byggs i kärnverkstadens arbetsyta för den
körande kärnan, och det bygget är en admins. Ett steg som körs har **Avbryt**, och jobbet slutar oftast direkt. **Kör
arbetsflödet** kör projektets CI-arbetsflöde för hand när arbetsflödet har en `workflow_dispatch`-utlösare; annars är
knappen av och sidan säger varför. Varje malls arbetsflöde har den utlösaren. **Installerat på denna NAS** listar
paketen som projektets testdriftsättningar installerat, med **Ta bort från denna NAS** för en admin. **Ta bort
projektet**, i menyn bredvid huvudets knappar eller i projektets meny på sidan Projekt, är för en admin eller för
utvecklaren vars Forgejo-konto har repositoryt. Du skriver först projektets namn; mappen försvinner, och
Forgejo-repositoryt, en App Builder-app med namnet och installerade paket ligger kvar. Sidan länkar sedan till
repositoryt.

**Inställningar** innehåller det bvsd sparar för projektet utanför dess mapp. För ett Makefile-, CMake- eller
QPKG-projekt visar det miljön som Bygg och Bygg om körs i och ändrar den. För en Makefile som bara skapar och bygger App
Builder-appar listar det varje app med miljön som dess rad i Makefile anger. Ett projekt som gör ett paket, eller vars
arbetsflöde kör `bvs repo publish`, har där reglaget **Publicera i App Center-förrådet**: på lägger `bvs repo publish` i
projektets CI till dess paket i förrådet; av hoppar CI-körningen över det steget med ett meddelande. Ett projekt utan
sparat val (en kopia av ett exempel, en klon) har det på. **Git** visar grenen, hur långt den ligger före eller
efter sin fjärr som senaste fetch lämnade den (sidan gör aldrig fetch), den senaste commiten och de ändrade sökvägarna.
**Filer** listar en mapp i taget; välj en fil för att läsa den, en `.qpkg` laddas ner. Redigering sker i redigeraren,
och mappen `.git` lämnas utanför.

**Recept** visar, för ett projekt med en egen mapp `recipes/`, recepten som dess appar tar: vart och ett med sin
version, den version i biblioteket som det ersätter när det har namnet på ett biblioteksrecept, och därunder vad
receptkontrollen hittade, med fil och rad. Ett recept som bvsd utelämnar har en rad med orsaken; är fler än tre
utelämnade på samma sätt räknar en rad resten. Det som kontrollen hittade om mappen `recipes` som helhet har en egen
rad. Ett klick öppnar receptets mapp i redigeraren; menyn kopierar också kommandot som kör samma kontroll i en
terminal på NAS:en: `bvs recipe lint` med projektets mapp. Kortet visas också när projektets `recipes` är en länk, en
fil, en mapp som bvsd inte kan läsa eller en mapp med bara länkar, och säger varför inget recept läses därifrån.

**Tjänst och paket** (ett QPKG-paket, eller ett Makefile-projekt med sitt paket i `qpkg/`, till exempel ett paket från
källkod) innehåller paketets start- och stoppskript som block, fälten i dess `qpkg.cfg` (**Paket**) och filerna som
skrivs från dem (**Skript**). **Spara** visar varje fils skillnader och committar dem sedan i projektets repository;
om projektet har ändrats under tiden, planera igen. **Redigera för hand** stänger av blocken, så att du redigerar
skriptet i redigeraren; **Koppla blocken igen** visar vad en ny skrivning skulle ersätta. **Uppdatera biblioteket**
för in `bvs-qpkg.sh` från den här Bucket & Code Server IDE i paketet, med dess skillnader. Ett projekt från före blocken erbjuder **Använd
block för det här skriptet**.

**Versioner** listar vad projektet kan bytas till, och **Byt till denna version** gör det:

| Version | Vad bytet gör |
|---|---|
| En `.qpkg` i `build/`, eller en App Builder-export | en testdriftsättning av den filen (admin) |
| App Builders bygge | aktiverar det (admin); App Builder behåller ett bygge |
| En version i paketrepository | gör den till den listade versionen (admin) |
| En git-tagg | checkar ut taggen i mappen |

Ett klick väljer en version; dess meny testdriftsätter också, publicerar, publicerar på ett webbmål eller laddar ner
en `.qpkg`. En tagg checkas ut som frikopplad HEAD, och **Tillbaka till main** i Git-kortet går tillbaka till grenen.
Bytet vägras så länge mappen har ändringar som inte är committade; meddelandet listar dem, och du committar eller
stashar dem först i redigeraren. Bocka för två versioner så listar **Jämför de två** filerna som den ena har och den
andra saknar, och de ändrade filerna. Två taggar, eller två paket, jämförs efter innehåll; ett paket mot en commit bara
efter storlek. På sidan **Paket** installerar en admin också en version från förrådet på denna NAS (**Installera på
denna NAS**), med testdriftsättningens kontroller.

### Din egen webbserver (webbmål)

Ett webbmål är där en admin publicerar ett paket eller en webbplats på sin egen webbserver: en mapp på denna NAS
(QTS:s Web-delning, som QTS:s Web Server levererar, eller en annan delad mapp) eller en rclone-fjärr (SFTP, FTP,
WebDAV, S3, inställd i säkerhetskopiornas `rclone.conf`), med den publika adress som levererar den. De finns på sidan
**Publicera**, under **Webbmål**: **Lägg till ett mål**, **Ändra**, **Ta bort** och **Testa**, som kopierar en liten
fil dit, hämtar den via den publika adressen och tar bort den igen.

Ett mappmål är en egen mapp i en delning (`/share/Web/minsajt`, aldrig en hel delning eller en volym), utanför
datamappen, eftersom en webbplatspublicering tar bort från målet det som webbplatsen inte längre har. Adressen börjar
med `http://` eller `https://` och har ingen användare eller lösenord.

Varje publicering läser tillbaka filen via den publika adressen: ett pakets `.qpkg` med dess `.sha256`, jämförd efter
sha256, eller en webbplats `index.html`, jämförd byte för byte. När adressen inte levererar det som kopierades
misslyckas jobbet med `web_check:` och båda värdena.

## CI-runners

CI-modulen kör Forgejo Actions: en arbetsflödesfil i ett repositorys `.forgejo/workflows/` körs på en runner när något
pushas. Den behöver Git-modulen. En admin slår på den under **Moduler**, **CI**, **Aktivera**. Jobbet registrerar
NAS:ens egen runner hos Forgejo, startar om Forgejo med Actions påslaget, och startar runnern; det slutar när runnern
har nått Forgejo.

### Runnern på NAS:en

- **Dess etiketter** är `bucketvs`, `qnap-x86_64` (eller `qnap-aarch64`) och `self-hosted`, plus de extra etiketter
  som en admin anger på sidan CI. Ett jobb vars `runs-on` nämner en av dem körs här, till exempel `runs-on: bucketvs`.
- **Den kör varje jobb på NAS:en själv, som admin**, inte i en container. Ett jobb har paketets verktyg (git, curl,
  make och resten), Node för JavaScript-actions som `actions/checkout`, och `bvs env run <env> -- <command>` för ett
  bygge i en miljö. Den som kan pusha ett arbetsflöde till ett repository kan därför köra kommandon som admin på
  NAS:en. En member eller viewer kan inte skapa, forka eller importera repositoryn, eller skapa organisationer, i
  Forgejo; developers och admins kan. En viewer pushar aldrig. Medan CI är på avvisas en members push till ett
  repository vars Actions är på, med skälet, och likaså en push med en deploy key. En members push, eller en push med
  en deploy key, till ett repository som ett konto under developer äger eller administrerar avvisas också, även när
  CI är av: ett sådant konto skulle själv kunna slå på Actions. bvsd stänger av Actions inom en minut i varje
  repository som en member eller viewer äger eller som ett sådant konto kan skriva i, och innan runnern startar när
  CI slås på.
- **Det som återstår** är en developers eller admins egen handling: att slå på Actions, eller starta ett arbetsflöde,
  i ett repository som en member skrivit i tidigare, eller att ge ett sådant konto admin-åtkomst till ett repository
  det skrivit i tidigare. En developer som slår ihop eller bygger en members commits kör dem också som admin.
- **Jobb samtidigt** är `ci.capacity` (1 som standard). Ett jobb som ingen runner online kan ta väntar i Forgejo.
- **Repositoryn som skapades innan CI var på** har Forgejos Actions avstängda, så ett pushat arbetsflöde startar
  ingenting: slå på dem i repositoryts **Inställningar**, **Enheter** (Actions). Repositoryn som skapas medan CI är på
  har dem.
- **Actions** som `actions/checkout@v4` laddas ner från `https://data.forgejo.org`, så NAS:en behöver internetåtkomst
  för arbetsflöden som använder dem. Runnern har ingen cache: `actions/cache` hittar ingenting och jobbet fortsätter.
- **Artefakter** (`actions/upload-artifact`) laddas upp till Forgejos egen adress (den på sidan Git), så NAS:en måste
  nå den adressen, och lita på dess certifikat när den är HTTPS.
- **Runnerns tillstånd** ligger i `<data>/runner`; dess logg är **runner** under **Loggar**. Att stänga av modulen
  stoppar runnern och stänger av Actions i Forgejo.

### Externa runners

En byggmaskin någon annanstans (en server, en VM) kan också ta jobb från den här Forgejo. På sidan CI, under
**Registrera en extern runner**, ger en admin den ett namn och får kommandona för Linux x86_64 och aarch64. De laddar
ner forgejo-runner 13.2.0 från code.forgejo.org, kontrollerar dess sha256, sparar runnerns token i `runner-token`
(läsbar bara för dess ägare) och startar runnern med etiketten `linux-amd64` (eller `linux-arm64`). Runnern visas i
listan direkt, offline tills kommandona körs. Token visas bara då. En sådan runner kör sina jobb på sin egen maskin,
som den användare som startade den, och når Forgejo på dess publika adress.

## SVN och Bucket

Modulen SVN och Bucket serverar Subversion-repositoryn på `/svn/<namn>` och buckets på `/bucket/<namn>`. En bucket är
en nätverksenhet (WebDAV) där varje sparad fil blir en revision, så att varje tidigare version av en fil kan läsas
eller läggas tillbaka. En admin slår på modulen under **Moduler**; sidan **SVN och Bucket** skapar, listar och tar
sedan bort båda typerna.

- **Kontona** är panelens. Behörigheter ställs in per repository: läsa och skriva, läsa, eller ingen, för varje konto,
  plus en standard för varje konto som inte är listat. Admins läser och skriver alltid; members och developers
  skriver där de har läsa och skriva; viewers läser som mest. Ett nytt repository ger ingen utom admins någon
  åtkomst förrän en admin ställer in den (personikonen på dess rad, **Behörigheter för `<name>`**).
  Under admin visar sidan var och en sin egen åtkomst till varje repository och bucket.
- **Fel lösenord** räknas som vid panelens inloggning: 5 fel lösenord inom 15 minuter spärrar det kontot från den
  adressen, och adressen själv, i 15 minuter.
- **Tvåfaktorsautentisering.** Ett konto med tvåfaktorsautentisering använder inte sitt lösenord för SVN eller WebDAV. Det
  skapar ett **applösenord** på sin kontosida (**Applösenord för WebDAV och SVN**): 25 slumpade tecken, visas en gång.
  Ett nytt ersätter det gamla; ett lösenordsbyte eller att stänga av tvåfaktorsautentiseringen tar bort det.
- **Att ta bort** ett repository flyttar det till `<data>/trash`, där jobbet `trash` tar bort det efter 7 dagar.

### SVN-repositoryn

```bash
svn checkout "https://<NAS-adress>:9951/svn/<namn>"
svn commit -m "…"
```

Sidan visar checkout-kommandot med repositoryts adress. Bakom en proxy följer adressen den publika URL:en, och med ett
SVN-värdnamn är den `/svn/<namn>` på det namnet. Ett repositorys **Historik** listar dess revisioner; en fil kan läsas
i vilken revision som helst, jämföras med en annan, och läggas tillbaka som en ny revision (**Återställ den här
versionen**, för konton med läsa och skriva).

### Buckets

- **Att spara är att committa.** En klient som sparar en fil skapar en revision med kontots namn och tiden; revisionen
  är märkt som gjord via WebDAV. Många klienter skriver först en tom fil och datan efteråt, så en sparning kan skapa
  två revisioner.
- **macOS-filer.** En bucket som skapats med **Neka macOS-filerna ._\* och .DS_Store** (standard) lagrar inte filerna
  `._*` och `.DS_Store` som Finder skriver bredvid det den kopierar. Klienten får inget fel, men filen blir aldrig en
  revision. Att ta bort en sådan fil är tillåtet.
- **Gå tillbaka.** Bucketens historik visar varje fils versioner; **Återställ den här versionen** sparar det gamla
  innehållet som en ny revision, så inget går förlorat.

### WebDAV-klienter och deras gränser

| Klient | Hur du ansluter | Anmärkningar |
|---|---|---|
| Finder i macOS | **Gå**, **Anslut till server**, `https://<NAS-adress>:9951/bucket/<namn>` | Finder låser en fil medan den skriver den; bucketen svarar på WebDAV-lås |
| rclone | en `webdav`-remote med `vendor = other` och bucketens adress | passar för kopior via skript |
| davfs2 (Linux) | `mount -t davfs https://<NAS-adress>:9951/bucket/<namn> /mnt/<mapp>` | panelens användarnamn och lösenordet eller applösenordet |
| Cyberduck, WinSCP | en WebDAV-anslutning (HTTPS) till port 9951, sökväg `/bucket/<namn>` | |
| curl | `curl -T fil -u <användare> https://<NAS-adress>:9951/bucket/<namn>/fil` | en uppladdning, en revision (eller två, se ovan) |
| Utforskaren i Windows | **Anslut nätverksenhet** | Windows WebClient skickar ett lösenord bara via HTTPS med ett certifikat som Windows litar på: lägg bucketen bakom en proxy med ett riktigt certifikat ([Bakom en omvänd proxy](#bakom-en-omvänd-proxy-plesk)); det självsignerade certifikatet räcker inte |

- Stora filer kapas inte: nginx sätter ingen storleksgräns för kroppen på `/bucket/` och skickar vidare uppladdningen
  allteftersom den kommer.
- En fil som bucketen vägrar att lagra (en macOS-fil ovan) besvaras ändå med `201` av WebDAV-servern, så en klient
  visar inget fel; filen finns inte i bucketen.

### Visa ett repository eller en bucket för personer utan konto

En admin kan göra ett SVN-repository eller en bucket publik med reglaget på dess rad på sidan **SVN och Bucket** (**På
webben**). Alla som har adressen kan då läsa den i en webbläsare, utan konto:

| Adress | Vad den visar |
|---|---|
| `https://<NAS-adress>:9951/svn-web/<namn>/` | ett SVN-repository |
| `https://<NAS-adress>:9951/bucket-web/<namn>/` | en bucket |

Radens länk **Visa på webben** öppnar den sidan. Den listar filerna och mapparna i den senaste revisionen eller en
äldre, visar en textfil med radnummer (upp till 1 MiB) eller en bild, och erbjuder varje fil för nedladdning.
**Historik** listar revisionerna med deras författare, meddelanden och ändrade filer. En revisions sida visar diffen
för varje fil den ändrade (upp till 20 filer på högst 1 MiB; de andra är länkar); vilken fil som helst kan jämföras
mellan två revisioner.

- **Bara läsning.** Sidorna kan inte ändra något. WebDAV-klienter och `svn` behöver fortfarande ett konto, även för
  ett publikt repository.
- **Bara det som är publikt.** Ett repository som inte är publikt, och ett namn som inte finns, svarar båda ”There is
  no public repository at this address”, så sidorna avslöjar inte vilka namn som finns.
- **Gränser.** En adress får öppna 60 sidor på en gång och 2 per sekund därefter, och ladda ner 2 filer åt gången;
  utöver det ber sidan dig försöka igen om en stund. En diff kapas vid 2 MiB.
- **Sökmotorer** ombeds att inte indexera sidorna. Sidorna är på engelska. De ser ut som panelen, mörka eller ljusa
  efter hur besökarens webbläsare är inställd.
- Bakom en proxy eller med ett SVN-värdnamn följer adressen repositoryts egen (den publika URL:en, eller
  SVN-värdnamnet med samma sökvägar).

## Redigerare och AI-verktyg

Modulen Redigerare kör VS Code i webbläsaren (code-server) för varje konto med rollen developer eller admin. En admin
slår på den under **Moduler**. Varje konto får en egen instans, som startar när kontot öppnar redigeraren och stoppas
efter en tid utan trafik.

**Redigerarens terminal är ett root-skal på NAS:en.** På QTS körs paketets processer som admin (uid 0), utom Forgejo och
httpd. Ge rollen developer bara till personer som du skulle ge NAS:ens admin-lösenord.

### Öppna redigeraren

- **Öppna redigeraren** på sidan Redigerarinställningar (eller `/ide/` på panelens adress, eller redigerarens
  värdnamn) öppnar arbetsytan i en ny flik. Den första begäran startar instansen; panelens inloggning kommer först
  när det inte finns någon session.
- Via det publicerade huvudvärdnamnet, så länge redigeraren inte är publicerad där, säger sidan
  Redigerarinställningar, fliken Redigerare, Översikt och **Öppna ett skal** att redigeraren bara öppnas från det
  lokala nätverket och länkar till dess LAN-adress (`https://<NAS-adress>:<HTTPS-port>/ide/`); för en administratör
  länkar de också till reglaget på sidan **Publicering**.
- Redigeraren öppnar `<data>/projects`, där exemplen under Redigerarprojekt lägger sina projekt. Kontots
  inställningar, tillägg och terminalhistorik sparas i `<data>/ide/<konto>` och dess hemmapp i `<data>/home/<konto>`.
- Terminalen har paketets verktyg först i `PATH`: git, svn, node, npm, rsync, curl, bash och resten.
  `bvs env shell <namn>` går in i en miljö från Verktygskedjor och `eval "$(bvs use <id>)"` gör en verktygskedja eller
  körmiljö redo. **Öppna ett skal** på sidan Verktygskedjor öppnar redigeraren med en terminal som redan är inne i den
  miljön.
- Aktiviteten **Redigerare**, och kommandopaletten, öppnar redigeraren med ett skal i en miljö eller med en apps mapp.
  Redigeraren visas i panelens flik Redigerare; på en telefon öppnas den i ett eget webbläsarfönster. Bara sidor på
  panelens egen adress får visa redigeraren inuti sig: paketet talar om det för webbläsarna i varje svar från
  redigeraren, så att en annan webbplats inte kan lägga redigerarens root-terminal under en egen sida.
- **Inaktivitetstid** (standard 30 minuter) stoppar en instans utan webbläsartrafik, men aldrig medan ett program som
  startats från dess terminaler, en AI-agent som ett tillägg startade (`claude` i Claude Code for VS Code, Codex,
  Gemini CLI) eller något som lämnats igång därifrån fortfarande körs. 0 stänger av stoppet vid inaktivitet. Ett konto
  kan stoppa sin egen instans på sidan Redigerarinställningar; en admin kan stoppa vilken som helst.
- **Minne och processer** på sidan Redigerarinställningar visar vad en instans kör och hur mycket minne den använder
  jämfört med NAS:ens, markerar det som håller den igång, avslutar en process med **Avsluta** och säger varför det
  senaste stoppet kom och vad det avslutade. Även en AI-agent som väntar vid sin prompt håller instansen igång:
  avsluta den där när den inte längre behövs.
- VS Codes vy **Ports** når en utvecklingsserver på NAS:en på `/ide/proxy/<port>/`; paketets egna loopback-portar
  avvisas där.
- **New recipe**, i menyn för ett projekts mapp `recipes`, eller för en receptmapp i den, i **Explorer**, frågar efter
  ett namn och skriver ett nytt recept där: `recipe.json` och `build.sh` från paketets startrecept. I kommandopaletten
  heter det **Bucket: New recipe** och fungerar medan en fil i ett projekt med en mapp `recipes` är öppen. Varje gång du
  sparar en fil i ett recept kontrollerar redigeraren projektets recept med `bvs recipe lint` och visar fynden i vyn
  **Problems**. Den varnar för startreceptets sha256 tills du skriver in din källas riktiga.

Redigeraren svarar bara sina egna sidor. En WebSocket, ett formulär eller ett skripts begäran som en annan sida skickar
med kontots session, från en annan webbplats eller från en annan port på NAS:en, får 403 och startar ingen instans; så
når en annan sida inte heller en utvecklingsserver bakom vyn **Ports**.

### Tillägg

- Tillägg installeras i redigerarens Extensions-vy (Ctrl+Skift+X). De kommer från Open VSX: webbläsaren söker på
  open-vsx.org och visar varje tilläggs sida och ikon från openvsx.eclipsecontent.org, och NAS:en laddar ned själva
  tillägget från open-vsx.org. Både webbläsaren och NAS:en behöver nå internet för det.
- Det första tillägget från varje utgivare frågar ”Do you trust the publisher …?”. **Trust Publisher & Install**
  installerar det; till dess visar tillägget ”Installing”.
- Varje konto har sina tillägg i `<data>/ide/<konto>/extensions`, och en paketuppdatering behåller dem.
- Paketet har med sig en uppsättning tillägg och formaterare, som redigeraren installerar för varje konto vid dess första
  start, och igen efter en paketuppdatering med en ny uppsättning. Med den färgar och formaterar redigeraren (**Format
  Document** i kommandopaletten) Markdown, skalskript, C, C++, Rust, Go, Pascal, Python, Perl, PHP, JSON, YAML, TOML,
  nginx-konfiguration, CSS, HTML, JavaScript och TypeScript. ShellCheck markerar problem i skalskript,
  systemd-enhetsfiler får färgning och komplettering, ett projekts `.editorconfig` bestämmer indraget, färgkoder som
  `#ff8800` eller `rgb(0, 128, 0)` visas i sin färg i varje fil, och **Hex Editor: Open Active File in Hex Editor** i
  kommandopaletten visar en fils byte.
- Rust formateras när Rust-körmiljön är installerad på sidan Verktygskedjor och kontots redigerare har startat igen; fram
  till dess säger Format Document i en Rust-fil att begäran misslyckades.
- På en ARM-NAS (aarch64-paketet) färgas Pascal, Perl och PHP men formateras inte: paketet har inget bygge av Free
  Pascal, Perl eller Mago för den.
- Ett tillägg ur uppsättningen som kontot tar bort i Extensions-vyn förblir borttaget, även efter en paketuppdatering,
  och ett som kontot uppdaterar behåller den nyare versionen. En standardformaterare som valts för ett språk (**Format
  Document With…**, sedan **Configure Default Formatter…**) förblir kontots val.
- Varje `.conf`-fil öppnas som nginx-konfiguration. Språknamnet i statusfältet byter en fil till ett annat språk.
- Ruff, som formaterar Python, säger en gång att inget tillägg för Python-miljöer är installerat. Det formaterar ändå.
- I redigerarens terminal installerar `code-server --install-extension <utgivare.namn>` också ett tillägg från Open VSX.
- Vissa tillägg ritar egna vyer, till exempel panelen i Claude Code for VS Code, hexredigeraren och
  Markdown-förhandsvisningen. Webbläsaren visar de vyerna bara när den litar på panelens certifikat. Med det
  självsignerade certifikatet som bara godkänts via webbläsarens varningssida förblir de tomma, och fliken Redigerare
  och sidan Redigerarinställningar säger det. Vilken som helst av de här vägarna löser det:
  - lita på NAS:ens certifikat på enheten: **Ladda ned certifikatet** på sidan Nätverk eller i det meddelandet, och
    lägg sedan till det bland systemets eller webbläsarens betrodda certifikat ([Certifikatet](#certifikatet));
  - en admin lägger till ett certifikat för NAS:ens namn på sidan Nätverk;
  - öppna redigeraren via det publicerade huvudvärdnamnet, när en admin publicerar den där.
- Claude Code for VS Code (utgivare Anthropic) installeras från Extensions-vyn, och dess panel frågar hur du loggar
  in hos Anthropic. **Claude Code: Open in Terminal** i kommandopaletten kör Claude Code i en terminal, och det
  fungerar med vilket certifikat som helst. VS Codes egna chattfunktioner är avstängda från start
  (`chat.disableAIFeatures`); den inställningen påverkar inte det här tillägget.

### Claude Code, Gemini CLI och Codex CLI

Under **AI-kommandoradsverktyg** på sidan Redigerarinställningar installerar, uppdaterar och tar varje konto bort de
här verktygen för sig självt:

| Verktyg | Installeras med | Kommando |
|---|---|---|
| Claude Code | Anthropics installationsprogram (`claude.ai/install.sh`), npm om det misslyckas | `claude` |
| Gemini CLI | `npm install -g @google/gemini-cli` | `gemini` |
| Codex CLI | `npm install -g @openai/codex` | `codex` |

- De hamnar i kontots hemmapp (`~/.local/bin`, `~/.npm-global/bin`), som finns i terminalens `PATH`; ett annat konto
  ser dem inte.
- Varje installation är ett jobb med sin logg på sidan Jobb. Inloggningen i varje verktyg (ett konto eller en
  API-nyckel) sker i verktyget självt, i redigerarens terminal.

### Koda med en AI-assistent

Varje projekt som **Nytt projekt** skapar innehåller en skill för AI-assistenter: `.claude/skills/qnap-dev/` och en
`AGENTS.md` som pekar på den. Skillen, på engelska, innehåller riktlinjer för allt som rör en QNAP-NAS: vad den är i
skalet (en rot på en RAM-disk, BusyBox, ingen systemd, ingen pakethanterare, `getcfg` och `setcfg`), lagring och
sökvägar, hur man bygger, signerar och publicerar med det här paketet (`bvs env run`, `bvs ldd`, `bvs qbuild`, App
Builder, kärnverkstaden, paketförrådet), portar, säkerhetskopior och vad den inte får föreslå, som `apt` på NAS:en eller
att tillåta osignerade appar i App Center. Den säger rakt ut att signering med en hårdvarutoken inte stöds och inte är
testad.

- Starta assistenten i projektets mapp (`cd <data>/projects/<namn>`), inte i `projects/`: varje verktyg letar i mappen
  det startar i.
- Claude Code laddar skillen från `.claude/skills/` när en uppgift behöver den. Codex CLI läser `AGENTS.md`. Gemini
  CLI läser `AGENTS.md` när projektets `.gemini/settings.json` innehåller
  `{"context": {"fileName": ["AGENTS.md", "GEMINI.md"]}}`.
- Paketet håller den aktuella skillen i `/usr/bin/bucketvs/share/skills/qnap-dev`. Ett projekt som skapades innan
  paketet hade den, eller ett projekt som kopierats från galleriet Exempel, får den när du kopierar den mappen till
  projektets `.claude/skills/`.
- Skillen hänvisar till QNAP Club Polands kunskapsbas (forum.qnap.net.pl) för vad NAS:en har och saknar.
- Paketets bygge skriver också skillen som `qnap-skill-<version>.zip`, samma filer, för bruk utanför redigeraren:
  packa upp den i ett projekts `.claude/skills/` eller i `~/.claude/skills/`. Skillens text är licensierad under CC BY
  4.0 (dess `LICENSE`): du får dela och bearbeta den med raden "QNAP guidelines skill by QNAP Club Poland /
  qnaputilities.com, CC BY 4.0".

## Verktygskedjor och miljöer

Sidan Verktygskedjor laddar ner det som behövs för att bygga programvara på NAS:en:

| Typ | Vad det är | Exempel |
|---|---|---|
| Rotfilsystem | ett Linux-system att packa upp i en miljö | Debian 12 och 13, Ubuntu 22.04 och 24.04, Alpine 3.22 |
| Korsverktygskedja | en kompilator som bygger för en annan processor | Bootlins verktygskedjor för aarch64, x86-64 och armv7, med glibc eller musl |
| Körmiljö | ett språk eller ett byggverktyg | Python, Go, Node.js, Zig, Rust, CMake, Ninja, Java (JDK) |
| QNAP | QNAP:s egna verktyg | QDK 2.5.0, för [`bvs qbuild`](#bygga-ett-qpkg-med-bvs-qbuild) och Exportera som QPKG |
| Kärnkällkod | ett Linux-kärnträd för [kärnverkstaden](#kärnverkstaden) | Linux 6.6.129 från kernel.org; QNAP:s GPL-kärnutgåva för QTS 5.2.3 |

Poster för en annan processor är dolda; ”Visa poster för andra processorer” listar dem, men de kan inte installeras.
Bootlins verktygskedjor körs på x86_64, så en ARM-NAS har ingen korsverktygskedja.

### Katalogen

Paketet har en inbyggd katalog. Den signerade fjärrkatalogen på `https://pub.qnaputilities.com/bucketvs/catalog.json`
kan lägga till poster utan ett nytt paket. bvsd använder den bara när dess ed25519-signatur stämmer med nyckeln som är
inbyggd i paketet och den inte är äldre än katalogen som används. ”Uppdatera katalogen” hämtar den direkt, och det
inbyggda cron-jobbet ”Uppdatering av verktygskedjekatalogen” hämtar den varje dag kl. 04:15.

### Installera och ta bort

Att installera är en admins uppgift, och visas med förlopp på sidan Jobb:

1. Arkivet laddas ner till `toolchains/cache/` i datamapp. En avbruten nedladdning fortsätter när installationen
   startas igen.
2. Dess sha256 kontrolleras mot katalogen. Vid en avvikelse tas filen bort.
3. En korsverktygskedja eller en körmiljö packas upp i `toolchains/<kind>/<id>` och dess arkiv tas bort. Ett
   rotfilsystem eller kärnkällkod stannar som arkiv; varje miljö eller arbetsyta för kärnan packar upp en egen kopia.
   QNAP publicerar sin GPL-kärnutgåva i två delar: båda laddas ner, var och en kontrolleras med sin egen sha256, och
   sätts ihop.

En full volym får installationen att misslyckas med ”no space left on” och volymens monteringspunkt.

”Ta bort” tar bort en installerad post. Miljöer som skapats från ett rotfilsystem är kopior och finns kvar.

### Använda en verktygskedja eller körmiljö

`bvs use <id>` skriver ut `export`-raderna (till exempel `PATH`) som gör en installerad korsverktygskedja eller
körmiljö användbar i ett skal:

```bash
eval "$(bvs use bootlin-aarch64-glibc-stable)"
```

Sidan Verktygskedjor visar samma rader under ”bvs use” för varje installerad post.

### Miljöer

En miljö är ett Linux-system som packats upp från ett rotfilsystem i `envs/<namn>` i datamapp. Den går att ändra:
`apt install build-essential` fungerar i en Debian- eller Ubuntu-miljö, och det du installerar stannar där.

- ”Ny miljö” (admin) laddar först ner rotfilsystemet när det inte är installerat, och packar sedan upp det.
- Så länge det inte finns någon miljö erbjuder listan Ubuntu 24.04 builder, den som appexemplen byggs i, med en knapp
  (admin): dess jobb syns i listan, och miljön dyker upp när jobbet är klart. Inget skapas av sig självt.
- Ett namn har 1 till 64 tecken: små bokstäver, siffror, `.`, `_` eller `-`, och börjar med en bokstav eller en
  siffra.
- En förinställning från galleriet Exempel installerar också paket med apt-get innan miljön visas: byggaren för
  Ubuntu 24.04 (standardbyggaren) och byggaren för Debian 12, båda fullständiga, med App Builders byggverktyg och
  patchelf; Clang/LLVM (LLVM 18), Fortran (gfortran 13), Kernel builder, .NET 8 SDK och Kotlin (Kotlin 1.3.31), alla
  på Ubuntu 24.04. Varje förinställnings glibc är högst 2.39, så det du bygger där körs på varje NAS som paketet körs
  på ([Vilka NAS-modeller en app körs på](#vilka-nas-modeller-en-app-körs-på)). När apt-get misslyckas lämnas ingen
  miljö kvar. Från ett skal: `bvs env create <namn> --from <rootfs-id> --package <namn> --package <namn>`.
- ”Klona” gör en fullständig kopia under ett nytt namn, till exempel för att prova en ändring utan att röra
  originalet.
- ”Exportera” packar miljön till `toolchains/exports/<namn>-<tid>.tar.zst`.
- ”Ta bort” tar bort den. bvsd vägrar medan ett skal eller en process körs i den. Filer i `projects/` hör inte till
  miljön och finns kvar.

Inuti en miljö:

- `projects/` i datamapp syns som `/projects`, och ett skal startar där;
- `HOME` är miljöns `/root`, och `LANG` är `C.UTF-8`;
- `/proc`, en skrivskyddad `/sys` och en liten egen `/dev` är monterade, och NAS:ens `resolv.conf` och `hosts`
  kopieras in;
- monteringarna hör till skalets eget monteringsnamnutrymme och försvinner när det avslutas, så ingenting blir kvar
  monterat på NAS:en.

Samma sak från ett skal (exemplen anropar `bvs` med namn, som ett cron-jobb och en SSH-session på NAS:en kan göra
medan paketet körs):

```bash
bvs env list
bvs env create deb12 --from debian-12-x86_64
bvs env shell deb12
bvs env run deb12 -- make -C /projects/hello
```

`bvs env shell` och `bvs env run` startar i den mapp du kör dem från. En mapp under `projects/` i datamapp är samma
mapp under `/projects` i miljön. Varje annan mapp (ett CI-jobbs utcheckning, en mapp i en utdelning) monteras på
`/work` och kommandot startar där. Från `/` startar de i `/projects`.

### Bygga ett QPKG med bvs qbuild

`bvs qbuild` bygger ett QPKG från den mapp du kör det i (en mapp med `qpkg.cfg`, som QPKG-mallen i Nytt projekt
skapar). Det kör QNAP:s `qbuild` i en Debian- eller Ubuntu-miljö. qbuild anropar systemprogram med deras fullständiga
sökvägar, och i miljön leder de sökvägarna till miljöns program i stället för NAS:ens egna. Paketet hamnar i mappens
`build/`.

```bash
bvs tc install qdk-2.5.0-x86_64      # en gång; qdk-2.5.0-aarch64 på en ARM-NAS
cd /share/CACHEDEV1_DATA/BucketVS/projects/MyTool
bvs qbuild                           # --env <namn> väljer miljön
```

Det använder miljön `ubuntu2404-builder` (exemplet ”Ubuntu 24.04 builder”), annars `debian12-builder`, annars en annan
Debian- eller Ubuntu-miljö, och behöver `rsync` i den. När något saknas stannar det och anger kommandot som lägger
till det, till exempel `bvs env run ubuntu2404-builder -- apt-get install -y rsync`. Argument efter `bvs qbuild` går
till qbuild. Innan qbuild körs säger `bvs qbuild` vilket [fall av kodsignering](#kodsignera-ett-qpkg) som gäller för
mappen.

En miljö har egna filer och verktyg. Allt i den körs som root, ser varje process på NAS:en och använder NAS:ens
nätverk.

### Kodsignera ett QPKG

App Center kontrollerar ett pakets kodsignatur när det installeras. För att signera behövs ett
kodsigneringscertifikat som QNAP har utfärdat till dig. `bvs qbuild` anger ett av tre fall på sin första rad, till
exempel `bvs: code signing, case 1 (a certificate as files): …`:

| Fall | I mappen finns | Vad som händer |
|---|---|---|
| 1, ett certifikat som filer | `certificate` och `private_key`, valfritt `ca_certs` (kedjan) | qbuild signerar paketet med `openssl`; miljön behöver `openssl` och `bsdextrautils` |
| 2, ett certifikat på en hårdvarutoken | `certificate_hsm` | stöds inte och är inte testat: `bvs qbuild` stoppar innan något byggs |
| 3, inget certifikat | ingen av de filerna | paketet byggs osignerat |

- **Fall 1.** Lägg de tre filerna bredvid `qpkg.cfg`. Saknar miljön ett program anger `bvs qbuild` kommandot, till
  exempel `bvs env run ubuntu2404-builder -- apt-get install -y openssl bsdextrautils`. Det vägrar en mapp med bara
  en av filerna `certificate` och `private_key` (qbuild skulle varna och bygga ett osignerat paket) och en mapp där
  någon av dem är tom. Håll filerna utanför git: QPKG-mallens `.gitignore` listar dem. I CI förvarar du dem som
  förrådets hemligheter och skriver dem till mappen bara under bygget.
- **Fall 2.** qbuild skulle läsa nyckelns plats på token från variabler som inte når det inne i miljön, och paketet
  har inte testats med en token. Bygg utan `certificate_hsm` och signera paketet på datorn som har token med QDK:s
  egna verktyg; QNAP-skillen för AI-assistenter (`references/signing.md`) beskriver QDK:s väg, som det här paketet
  aldrig har kört.
- **Fall 3.** På en enhet med QTS 6.1 installerade `qpkg_cli -m` av ett osignerat paket ingenting, medan
  `sh <fil>.qpkg` i en delad mapp installerade och startade det. [Paketförrådet](#paketrepository) tar emot det bara medan en
  admin tillåter osignerade paket, och App Center på en annan NAS installerar det bara om dess ägare tillåter appar
  utan giltig digital signatur, vilket det här paketet aldrig rekommenderar. **Exportera som QPKG** ger alltid det här fallet.
- `qbuild --sign` lägger till en GnuPG-signatur, som inte är den kodsignatur som App Center och förrådet läser.

## App Builder

App Builder kompilerar utvalda program till en enda mapp, appens prefix (som standard `/usr/app/my_app_prefix`), inuti
en miljö.

Fliken **Exempel** under **Appar** har färdiga appar, miljöer, CI-arbetsflöden, cron-jobb och redigerarprojekt.
**Visa koden** på ett kort visar vad exemplet gör innan du använder det, för alla roller: filerna i ett redigerarprojekt,
arbetsflödesfilen, cron-jobbets kommando, eller för en app dess recept i byggordning med varje recepts `build.sh`
och `recipe.json`. Visningen är skrivskyddad och visar textfiler; en miljö har ingen fil, så dess kort har ingen
sådan knapp. Att använda ett exempel kräver rollen developer, och en miljö rollen admin: en miljös kort visar inte
**Använd det här exemplet** för en developer.

### Recept

Varje program byggs från ett recept. Ett recept anger sin källa med en sha256, de recept det beror på, byggverktygen
som miljön behöver, och en kontroll som visar att resultatet fungerar (till exempel `bin/bash --version`). Det finns
recept för bibliotek (zlib, openssl, ncurses, readline med flera), skal (bash, zsh, busybox), verktyg (coreutils,
curl, git, jq, rsync, tmux, htop, nano med flera), servrar (nginx, redis, openssh, dropbear) och ett språk (lua).

- Ett recept byggs först efter de recept det beror på.
- Ett nytt bygge återanvänder ett recepts resultat så länge dess indata är oförändrade (källan, receptet, dess
  beroenden, miljöns kompilator och C-bibliotek, prefixet, och om det länkas dynamiskt eller statiskt) och varje fil
  det installerade finns kvar i prefixet.
- Länkningssättet avgör hur program hittar sina bibliotek. **dynamisk** ger varje program en RUNPATH på
  `<prefix>/lib`. **flyttbar** skriver den relativt till programmets egen mapp (`$ORIGIN/../lib`), så att trädet
  hittar sina bibliotek i vilken mapp som helst; sökvägar som kompilerats in i program, till exempel terminfo-mappen,
  anger fortfarande prefixet. **bundle** är flyttbar och kopierar dessutom in i `lib` de bibliotek som programmen
  laddar från byggmiljön (till exempel libstdc++), så att appen bara behöver NAS:ens C-bibliotek. **statisk** länkar
  statiskt de recept som stöder det. Att byta mellan dynamisk, flyttbar och bundle bygger inget på nytt.
- En statisk app avvisar recept som inte kan länkas statiskt (openssh, dropbear och tmux), och anger varje med skälet,
  om inte appen är inställd på att bygga dem som bundle. Sidan Ny app och **Ändra** erbjuder alla fyra sätten och, för
  en statisk app, det valet.
- Ett statiskt program som slår upp användare, grupper eller värdnamn läser dem bara från NAS:ens egna `/etc/passwd`,
  `/etc/group`, `/etc/hosts` och DNS, oavsett vad `/etc/nsswitch.conf` anger, så konton från en domän eller LDAP är
  okända för det. Bygg sådana program dynamiskt när de kontona spelar roll. Panelen varnar när en statisk app
  innehåller ett sådant.
- Efter det sista receptet körs varje recepts kontroll igen över det färdiga prefixet.
- Konfigurationsfiler under prefixets `etc/` överlever ett nytt bygge: en redigerad fil stannar, och den nya
  standardfilen läggs bredvid som `<file>.bvs-new`.

### Receptuppdateringar

Nya och uppdaterade recept kommer också som en signerad katalog från pub.qnaputilities.com, så att de når NAS:en före
nästa version av Bucket & Code Server IDE. bvsd söker efter en nyare katalog en gång om dagen. Den används bara när signaturen
stämmer med nyckeln som är inbyggd i bvsd, varje fil stämmer med katalogens lista och recepten är nyare än de som kom
med paketet; en katalog som inte klarar en kontroll används aldrig. Medan en katalog används markerar Ny app recepten
den för med sig som **ny i katalogen** eller **uppdaterad av katalogen**.

Kortet **Receptbibliotek** på sidan Appar visar vilket bibliotek byggen använder (**Paketets bibliotek** med paketets
version, eller **Katalog** med katalogens version) och den senaste kontrollen med dess resultat. En admin har två
knappar där; den andra visas medan en katalog används:

- **Sök efter receptuppdateringar** kontrollerar direkt i stället för att vänta på den dagliga kontrollen.
- **Använd paketets bibliotek** går tillbaka till recepten som kom med Bucket & Code Server IDE. Katalogen ligger åt sidan tills en
  nyare kommer; då använder byggen den nyare.

Efter ett byte återanvänder ett nytt bygge varje recept vars filer inte har ändrats. Före varje bygge kontrollerar
bvsd katalogens filer igen. Har någon ändrats på NAS:en stoppar bygget innan något körs, och byggen använder den
föregående katalogen eller paketets bibliotek.

### Bygga en app

**Appar**, **Ny app** (rollen developer) frågar efter ett namn, prefixet (`/usr/app/<namn>` om du inte väljer ett
annat), miljön som appen byggs i (en Debian- eller Ubuntu-miljö; galleriet Exempel skapar ”Ubuntu 24.04 builder”,
som sidan väljer först), målet (den här NAS:ens arkitektur, eller aarch64 eller armv7 som korsbygge), vilka
NAS-modeller den körs på, länkningssättet och recepten. De recept
som de beror på läggs till i byggordning.

En app kan också ta recepten från ett projekt som har en egen mapp `recipes/`. Välj projektet i **Recept från ett
projekt** i steget **Paket**. Projektets recept står först i listan, under projektets namn och märkta **projekt**, och
sedan följer bibliotekets. Ett recept från projektet med samma namn som ett recept i biblioteket ersätter det i den
här appen och visar vilken version i biblioteket det ersätter. Ett recept som projektet utelämnar nämns med orsaken.
Ett valt recept som saknas i projektets lista nämns under valet och utelämnas ur appen; det kommer tillbaka när du
väljer en lista som har det. Appens sida visar projektets namn, och en utvecklare öppnar projektvyn därifrån. En
viewer ser recepten i appens senaste bygge i den ordning dess logg nämner dem, vart och ett med sitt tillstånd och sin
logg; före det första bygget finns ingen ordning att visa.

Varje länkningssätt är ett kort, med en bild av var programmen hittar sina bibliotek, vad sättet kostar i storlek, i
uppdateringar och i var appen körs, och vilka recept som stöder det. Innan du väljer recept räknar korten hela
receptbiblioteket; när du går tillbaka till det första steget räknar de recepten i ditt bygge. För en statisk app
väljer du vad som händer med recept som inte kan länkas statiskt: bygg dem som bundle, eller utelämna dem.

- **Bygg** (eller **Bygg om**) kör ett jobb: det laddar ner varje källa och kontrollerar dess sha256, installerar de
  byggverktyg som recepten behöver i miljön, bygger i en kopia av appens föregående bygge, och kontrollerar varje
  program.
- Ett bygge som misslyckas, avbryts eller störs lämnar appen som den var: aktivering, nedladdning och export
  fortsätter att använda det senaste bygget som klarade sig.
- Ett bygge av en app körs åt gången, och ett bygge väntar medan program från den aktiva appen körs (stoppa dem
  först).
- Appens sida visar byggordningen, varje recepts tillstånd och logg, filerna under prefixet, och arkivet för det
  senaste lyckade bygget (**Ladda ner**, en `.tar.zst`).
- **Ändra** på appens sida ställer in en annan miljö, vilka NAS-modeller den körs på, ett annat länkningssätt,
  projektet som den tar recept från eller andra recept; nästa bygge tillämpar det.
- **Beroenden**, en flik på appens sida, visar vad varje ELF-fil i det senaste bygget behöver och var NAS:ens laddare
  hittar det, läst utan att något körs. Ett saknat bibliotek, en version som biblioteket inte definierar, eller en
  RUNPATH som pekar utanför appen listas som ett fynd med sin lösning. En developer kör en lösning med dess knapp:
  **Lägg till … och bygg**, **Byt till … och bygg**, **Bygg igen**, **Patcha RUNPATH**, **Ange tolken**, **Välj
  en annan miljö** eller **Bygg bara för denna NAS**. En lösning utan knapp (installera ett paket i en miljö, bygga för en annan maskin) är en mening
  att agera efter. Under fynden ritas varje fil och vad den behöver som en graf (program, appens bibliotek, NAS:ens
  bibliotek och de saknade i kolumner; en streckad linje är en version som biblioteket saknar, en prickad linje ett
  bibliotek som inte hittas någonstans) eller som ett träd; välj en fil för dess uppgifter. På NAS:en skriver
  `bvs deps <app>` ut samma sak.
- **ELF-inspektör** (Verktygskedjor, rollen developer) kontrollerar en fil: från en apps bygge, från projektmappen
  eller från en miljö, och för en admin vilken fil som helst på NAS:en, så som den skulle köras på den här NAS:en
  eller i en miljö. `bvs ldd <file>` gör samma sak på NAS:en (`--env <name>` för en miljö).
- **Varje bygge** kör samma kontroll över sitt resultat innan det ersätter appen, och misslyckas vid ett problem som
  stoppar ett program på den här NAS:en, eller vid ett program som behöver en nyare glibc än appen tillåter, med
  problemet och dess lösning i jobbets meddelande.
- **Patchverktyg** (fliken Beroenden) sätter RUNPATH (appens `lib`, formen med `$ORIGIN`, eller en mapp i appen) eller
  programtolken för utvalda filer i det senaste bygget, med miljöns patchelf, på en kopia som ersätter bygget bara när
  det lyckas. **Förhandsgranska** visar varje fil före och efter och vilka bibliotek den nya RUNPATH inte hittar i
  appen; **Tillämpa patchen** kör den. Nästa bygge skriver RUNPATH igen enligt appens länkningssätt.

Ett Qt-bygge kör Qts egna verktyg (moc, rcc och, för översättningar, Linguists lrelease). I ett korsbygge bygger
Qt-recepten (`qtbase`, `qttools`) därför först de verktygen för den här NAS:en, i `host/` under prefixet, och sedan Qt
för målet; recepten som byggs på Qt kör verktygen därifrån. Inget på målet kör `host/`. Det hör till appens bygge, så
arkivet och **Exportera som QPKG** innehåller det också.

### Egna recept

När receptbiblioteket saknar ett recept för ett program kan ett projekt ha ett eget. Recepten ligger i projektets mapp
`recipes/`, i bibliotekets format, och bara de appar som anger projektet bygger dem. Ett paket blir till i fem steg:

1. **Skapa projektet.** I [Nytt projekt](#nytt-projekt) skapar mallen **Package from source** (paket från källkod) en
   mapp med ett startrecept som heter som projektet, en Makefile för två appar (en för den här NAS:ens processor, en
   för aarch64, ett korsbygge på en x86_64-NAS) och paketets start- och stoppskript från steget **Tjänst**.
2. **Skriv receptet.** **New recipe** i redigeraren lägger till ett recept till från samma startrecept
   ([Öppna redigeraren](#öppna-redigeraren)). Skriv programmets riktiga källadress och dess sha256 i `recipe.json`
   (`curl -fsSL <adress> | sha256sum` i redigerarens terminal skriver ut summan), och byggstegen i `build.sh`. En
   receptmapp innehåller `recipe.json`, `build.sh` och den vendorfil som `recipe.json` anger, inget annat, så en patch
   läggs i `build.sh` som here-document.
3. **Kontrollera det.** Varje gång du sparar en fil i ett recept kontrolleras projektets recept och fynden visas i
   vyn **Problems**; `make lint` i terminalen och kortet **Recept** i [projektvyn](#projektvyn) ger samma fynd.
   Kontrollen läser `recipe.json` och tolkar `build.sh` med `bash -n`. Den kör aldrig receptet.
4. **Bygg.** **Bygg** i projektvyn skapar de två apparna när de saknas och bygger dem efter varandra. Ett bygge läser
   projektets recept en gång, när det startar, så en fil som sparas senare väntar på nästa bygge. Ett recept i projektet
   med samma namn som ett recept i biblioteket ersätter det bara i det här projektets appar, och byggets logg säger det.
5. **Packa och installera.** `make qpkg` i redigerarens terminal packar varje apps senaste lyckade bygge i paketet
   med QDK från Verktygskedjor och utelämnar en app som inte har något. Med kodsigneringsfilerna i `qpkg/` bredvid
   `qpkg.cfg`, eller i en mapp som `QPKG_CERT_DIR` anger, blir paketet signerat
   ([Kodsignera ett QPKG](#kodsignera-ett-qpkg)), och **Testdriftsättning** i projektvyn (admin) installerar det på den
   här NAS:en.

Några regler gäller för ett projekts recept:

- Ett recept som projektet utelämnar (en extra fil i mappen, en länk, en fil över sin storleksgräns) nämns med orsaken
  på kortet Recept och av kontrollen, och ett bygge som behöver det nekas.
- När projektets mapp byter namn eller tas bort byggs dess appar inte: bygget svarar ”Det finns inget projekt ’…’” tills
  **Ändra** på appens sida anger projektets nya namn eller **Inget: bara biblioteket**.
- Ett projekts recept körs som root i byggmiljön, liksom bibliotekets. Varje utvecklare kan skriva och bygga dem, på
  samma sätt som varje utvecklare kan köra ett projekts Makefile genom Bygg. En viewer ser namnen på en apps recept i
  byggets logg, aldrig receptfilerna.
- Ett projekts recept stannar i projektet. Det kommer in i receptbiblioteket, och i den signerade katalog som varje NAS
  hämtar, bara genom en granskad ändring i Bucket & Code Server IDE själv.
- Ett recept vars bygge behöver paket från npm, Go eller Cargo listar dem i en vendorfil. Den listan skriver
  `npm-vendor.py`, `go-vendor.py` och `cargo-vendor.py` i `/usr/bin/bucketvs/share/bucketvs/tools/`; de behöver en
  Python-körmiljö från [Verktygskedjor](#verktygskedjor-och-miljöer).

### Vilka NAS-modeller en app körs på

Ett program som byggts mot glibc startar bara på en NAS vars glibc är minst lika ny som den nyaste version programmet
ber om. Paketet räknar med glibc 2.39 eller nyare på varje NAS det körs på (QTS 6.0, QuTS hero 6.0 och nyare): dess
glibc-golv. 2.39 är glibc i Ubuntu 24.04 och i QuTS hero 6.0.1, läst ur den firmwarens egen `/lib/libc.so.6`; QNAP publicerar ingen glibc-version, och dess versionsinformation tar inte upp någon QTS 6.0. Test-NAS:arna med QTS 6.1.0 och QuTS
hero 6.1.0 har 2.43.

**Körs på** i den nya appen och i **Ändra** väljer ett av två:

- **Varje NAS som paketet körs på** (standard): inget program får behöva en glibc över 2.39. Bygg en sådan app i en
  miljö med glibc 2.39 eller äldre, som Ubuntu 24.04 builder (2.39) eller Debian 12 builder (2.36). Det är valet för
  **Exportera som QPKG** och paketrepositoryt.
- **Bara denna NAS**: programmen får behöva den här NAS:ens glibc, för programvara som behöver en nyare. En sådan app
  byggs för den här NAS:ens arkitektur och exporteras aldrig som QPKG.

Ett korsbygge (aarch64 eller armv7) är alltid för varje NAS. Den nya appen varnar när den valda miljöns glibc ligger
över det appen tillåter. Efter varje bygge läser bvsd den glibc-version som varje program och varje bibliotek ber om,
även i ett korsbygge. En fil över gränsen får bygget att misslyckas, och lösningarna nämns: en annan miljö
(**Välj en annan miljö**), länkningssättet static eller **Bygg bara för denna NAS**. Appens sida säger vilken glibc
dess senaste lyckade bygge behöver, och fliken **Beroenden** listar varje fil över gränsen.

På NAS:en kör `bvs tree-deps <prefix> --tree <mapp> --glibc-max 2.39` samma kontroll över vilket appträd som helst.

### Aktivera en app på NAS:en

**Aktivera** (admin) gör prefixet till en länk till appens senaste lyckade bygge, så att dess program körs på NAS:en
från `/usr/app/<namn>/bin`. Aktiveringen ersätter aldrig något som den inte själv skapat: en mapp, en fil eller en
annan länk vid prefixet avvisas med skälet. QTS systemdisk byggs om vid varje uppstart, så paketet skapar länkarna
igen vid varje start. **Inaktivera** (admin) tar bort länken; att ta bort appen inaktiverar den först och flyttar den
till papperskorgen i 7 dagar. En developer kan bara ta bort en app medan den inte är aktiv. En app som byggts för en
annan arkitektur kan inte aktiveras här; ladda ner dess arkiv för en NAS av det slaget.

### Exportera en app

**Exportera som QPKG** (admin) packar det senaste lyckade bygget som ett eget QPKG, som installerar appen på en annan
NAS utan det här paketet. Det avvisar en app som byggts bara för den här NAS:en, och stannar före packningen när ett
program i bygget behöver en glibc över 2.39 (se [Vilka NAS-modeller en app körs
på](#vilka-nas-modeller-en-app-körs-på)). Det kräver QDK: installera ”QNAP QDK 2.5.0” på sidan Verktygskedjor, fliken
QNAP. Tills QDK är installerat visas inte knappen och appens sida säger var du hämtar det. Exporten kör qbuild i
appens miljö, på samma sätt som [`bvs qbuild`](#bygga-ett-qpkg-med-bvs-qbuild). Varje bygge installerar `rsync` där;
för en app som senast byggdes med en äldre version av paketet anger avvisningen kommandot som lägger till det. Det
exporterade paketet skapar länken för sitt prefix vid start och tar bort den vid stopp. Det är inte kodsignerat:
jobbets logg anger [fall 3](#kodsignera-ett-qpkg), liksom en rad under knappen. I en SSH-session ställer
`/etc/init.d/<namn>.sh disable` och `enable` in det exporterade paketets reglage i App Center och lämnar prefixets
länk som den är. Vid varje start lägger det exporterade paketet också till en rad i `/etc/profile` och
`/root/.profile` som sätter appens `bin` och `sbin` i `PATH` för en SSH-inloggning, efter NAS:ens egna kommandon, för
admin och varje annat konto som får logga in; en borttagning tar bort raden igen.

## Paketrepository

Paketet håller ett App Center-repository: QPKG-paket som publiceras där kan installeras på andra NAS-enheter från App
Center, som apparna i vilket repository som helst.

- **Adressen.** `bvs repo list` skriver ut den (och `GET /api/v1/repo`): `<base>/repo/repo.xml`, där `<base>` är den
  publicerade värdnamnet för paket (annars det publicerade huvudvärdnamnet) medan paketet är publicerat på internet
  ([Publicera på internet](#publicera-på-internet-cloudflare-tunnel)), annars den publika URL:en när en sådan är
  inställd, annars `http://<NAS-adress>:9950` (`https://…:9951` när vanlig HTTP bara omdirigerar). På den andra
  NAS:en: App Center, **Inställningar**, **App-repository**, **Lägg till**, och den adressen.
- **Publicering.** `bvs repo publish <file.qpkg>` (på NAS:en, som root) eller `POST /api/v1/repo/packages` med filen
  som kropp (rollen developer). Arkitekturen kommer från QDK-filnamnet `<name>_<version>_<arch>.qpkg` (`x86_64`,
  `arm_64`, `arm-x41`), eller `--arch`. Namn, version, beskrivning och författare kommer från paketet självt;
  `PUT /api/v1/repo/packages/<name>/meta` och `…/icon` (en PNG, admin) ändrar vad App Center visar. Ett paket får inte
  heta `default`: det är namnet på repositoryts egen ikon.
- **Bara signerade paket.** Ett paket utan kodsignatur avvisas, eftersom App Center bara installerar sådana paket på
  en NAS som är inställd på att tillåta dem. Repositoryt räknar ett paket som signerat när dess kodsigneringsblock är
  en PKCS#7-signatur med ett certifikat och en undertecknare. Det kontrollerar inte signaturen eller dess certifikat
  mot QNAP:s; det gör App Center när det installerar paketet. En admin kan slå på `repo.accept_unsigned` i
  inställningarna för ett nätverk där det är känt; sådana paket märks i sin beskrivning. Paket som App Builder
  exporterar är inte signerade, så de behöver den här inställningen.
- **Versioner.** Varje version förblir nedladdningsbar, men App Center ser en version per paket, den som en admin
  listar. En admins första version av ett paket listas direkt; en senare när admin flyttar den
  (`POST /api/v1/repo/packages/<name>/latest`, eller `bvs repo publish --latest`). En developers version, även ett
  nytt pakets första, listas ingenstans förrän en admin gör en version till den senaste: varje NAS som lagt till
  repositoryt installerar den listade versionen som root. Att ta bort en version (admin) tar bort alla dess
  arkitekturer; när det var den listade listas ingen version förrän en admin väljer en annan.
- **Uppladdningar.** Två uppladdningar kopieras åt gången; repositoryt avvisar en som skulle lämna mindre än 256 MiB
  ledigt på datavolymen. Repositoryt ingår inte i en säkerhetskopia: publicera paketen igen efter en återställning.
- **I panelen.** Sidan **Paket** visar adressen att kopiera, paketen med sina versioner och om de är signerade; en
  utvecklare laddar upp ett QPKG där, och en admin listar en version som den senaste och tar bort en version. Dess kort
  **Kodsignering** visar de [tre fallen](#kodsignera-ett-qpkg), hur många listade versioner som saknar signatur, och
  adminens brytare för osignerade paket, som frågar innan den slås på. En apps sida visar dess pipeline (bygga,
  exportera som QPKG, publicera) med knappen **Publicera**.

## Kärnverkstaden

Kärnverkstaden bygger kärnmoduler för den kärna som NAS:en kör, kontrollerar var och en mot den kärnan, och laddar
den. QNAP har inte publicerat källkoden till sina nuvarande kärnor (dess GPL-utgåvor slutar vid QTS 5.2.3), så
verkstaden läser vad den körande kärnan visar om sig själv och konfigurerar ett kärnträd som passar den.

### Vad du behöver

- Miljön Kernel builder från galleriet Exempel (Ubuntu 24.04 med GCC 13 och kärnans byggverktyg). En modul måste
  byggas med samma huvudversion av GCC som kärnan; verkstaden jämför dem.
- Rollen admin, och root i en terminal: kommandona `bvs kernel` använder bvsd:s CLI-socket eller laddar moduler.

### Profilen

`bvs kernel profile` visar vad den körande kärnan är: dess release (`6.6.129-qnap`), kompilatorn som QNAP byggde den
med, vermagic för QNAP:s egna moduler, storleken på `struct module` i dem och var init och exit ligger, om moduler
måste vara signerade, och de inställningar som ett kärnträd får för att passa den.

### Arbetsytan

`bvs kernel prepare` skapar arbetsytan för den körande kärnan i `kernels/<release>` i datamappen:

1. Den tar den kärnkällkod som katalogen har för den här versionen (`bvs kernel sources`): QNAP:s eget GPL-träd när
   QNAP publicerat ett, annars trädet från kernel.org, som saknar QNAP:s egna ändringar. `--source` väljer ett annat.
2. Den konfigurerar trädet: med QNAP:s konfiguration för den här modellen när trädet är QNAP:s, annars med profilens
   inställningar. `--option NAME=m` lägger till en inställning, till exempel en drivrutin.
3. Den förbereder trädet för att bygga moduler (`--full` bygger i stället hela kärnan, vilket tar mycket längre tid
   och låter kontrollen se kärnans exporterade symboler).
4. Den kontrollerar att trädet bygger för exakt den körande kärnans release.

Den körs som ett jobb på sidan Jobb. En misslyckad prepare behåller trädet från den förra.

### Bygga en modul

- Din egen modul är en mapp i `projects/` med en `Kbuild`-fil. `bvs kernel make` i den mappen (eller
  `bvs kernel make --project <folder>`) bygger den. Exemplet ”Kernel module” är ett sådant projekt.
- En drivrutin i kärnan som QNAP inte levererar byggs från sin katalog i kärnträdet:
  `bvs kernel make --dir drivers/usb/serial`. Exemplet ”USB serial driver ch341” bygger drivrutinen ch341 på det
  sättet; dess inställning kommer först med `bvs kernel prepare --option USB_SERIAL=m --option USB_SERIAL_CH341=m`.

De moduler som ett bygge skapar sparas i `kernels/<release>/modules/`. En modul som QNAP levererar för den här kärnan
sparas inte: QNAP:s egen kopia förblir den som laddas. `bvs kernel make --build-only` sparar inget där: modulen
stannar där den byggdes. CI-arbetsflödena i kärnmallarna i Nytt projekt bygger så.

### Kontrollen och laddningen

`bvs kernel check <module>` jämför en modul med den körande kärnan: vermagic, storleken på `struct module` och var
init och exit ligger i den (mot QNAP:s egna moduler), om en signatur krävs, de moduler den beror på, och varje symbol
den behöver. Varje fynd säger vad som inte stämmer och vad du ska göra. Slutstatus 3 betyder att modulen inte får
laddas.

`bvs kernel load <module>` kör kontrollen igen och laddar modulen, och de moduler den beror på först (QNAP:s egna från
NAS:en, eller dina). En modul med ett fel i kontrollen laddas aldrig. `bvs kernel unload <module>` tar bort den; en
modul som används förblir laddad. Varje laddning och urladdning skrivs till `log/kernel-modules.log`.

QNAP:s kärna listar inte sina datasymboler, så kontrollen kan inte slå upp symboler som `jiffies`; den anger dem som
varningar. Om en av dem saknas avvisar kärnan modulen när den laddas.

### Moduler i en app

En app kan ange moduler från arbetsytan. Att aktivera appen laddar dem innan dess länk skapas, och varje start av
paketet laddar dem igen när panelen är uppe; sidan Kärnor visar en laddning som fortfarande pågår. Att inaktivera den
laddar ur dem först; en modul som används håller appen aktiv.

- Om NAS:en startade om medan moduler laddades, laddar nästa start inga och visar en avisering: ladda dem för hand
  eller aktivera appen igen.
- Om NAS:en stannade utan paketets ordnade stopp (en krasch, ett strömavbrott eller en hård återställning) under en
  uppstart där paketet laddade moduler, laddar nästa start inte de modulerna, eftersom en av dem kan ha orsakat
  kraschen. Aviseringen och sidan Kärnor anger dem. Att ladda en för hand, eller aktivera dess app igen, låter starten
  ladda den igen. En vanlig avstängning eller omstart av NAS:en stoppar paketet i ordning och ändrar ingenting.
- En modul vars start aldrig tar slut (en drivrutin som väntar på sin hårdvara) låter panelen fortsätta fungera. En
  avisering anger den efter en minut; andra laddningar och urladdningar väntar på den, och en omstart av NAS:en
  avslutar den.

Efter en QTS-uppdatering till en annan kärna måste modulerna byggas om i den nya kärnans arbetsyta. Samma sak gäller
efter en återställning till en annan datamapp: `kernels/` ingår inte i en säkerhetskopia.

### I panelen

Sidan **Kärnor** visar den körande kärnans profil, katalogens kärnkällkod, arbetsytan och dess moduler. En admin
förbereder arbetsytan där (en källa, miljön, extra inställningar, hela kärnan eller inte) och bygger moduler från en
projektmapp eller en katalog i trädet; båda körs som jobb. **Kontrollera** (developer) visar varje fynd med dess
lösning; **Ladda** och **Ladda ur** (admin) gör det som `bvs kernel load` och `unload` gör, och en avvisad laddning
visar kontrollen som stoppade den. En `.ko`-fil var som helst under datamappen kan kontrolleras via sin sökväg.

## Cron-jobb och operationer

Sidan Jobb har två listor: schemalagda jobb (cron) och operationer (de långa jobb som bvsd kör, till exempel
installationer och flyttar).

### Schemalagda jobb

En developer skapar och ändrar sina egna jobb; en admin ändrar alla. Ett jobb har:

- Schema: fem cron-fält (`0 3 * * *`), sex med sekunder först, eller en deskriptor (`@daily`, `@hourly`, `@every 6h`).
  Ett prefix `CRON_TZ=<zone>` väljer en annan tidszon; utan det körs jobbet i NAS:ens tidszon, som visas högst upp på
  sidan.
- Kommando: körs som root av paketets `bash -lc`. Flera rader körs som ett skript, och dess utdata blir körningens
  logg.
- Var det körs: på NAS:en, eller inuti en miljö (med miljöns `bash`, eller `/bin/sh` där den inte har någon).
- Arbetsmapp: relativt till `projects/` i datamapp, eller en fullständig sökväg. Inuti en miljö syns bara `projects/`,
  som `/projects`.
- Tidsgräns: i sekunder (0: ingen). En körning som fortfarande pågår efter den stoppas och markeras som att
  tidsgränsen överskreds.
- Medan en körning pågår: nästa hoppas över, eller den väntar (högst en väntar).
- Vid fel: en misslyckad körning eller en som överskred tidsgränsen skickar en [avisering](#aviseringar).

Varje jobb behåller sina senaste 100 körningar med slutet av deras utdata (4 KB). Den fullständiga loggen för en
körning sparas i 30 dagar.

Ett jobb körs som root för sin ägares räkning, med ägarens hemmapp som `HOME`, så det körs bara medan ägaren är en
aktiv developer eller admin. Medan ägaren är inaktiverad eller har rollen member eller viewer registreras var och en
av jobbets tider som en överhoppad körning som säger varför, till exempel ”its owner ola is disabled”, och **Kör nu**
svarar med samma skäl. Ingen avisering skickas. En körning som pågår när ägaren inaktiveras eller får en roll under
developer stoppas. Jobbet körs igen när kontot aktiveras, eller blir developer igen. Att ta bort ett konto tar bort
dess jobb. Inbyggda jobb körs vad som än händer med ett konto.

När ett kommando avslutas fortsätter processer som det startat i bakgrunden att köras. Vid en överskriden tidsgräns,
när jobbet tas bort eller när paketet stoppas får körningens hela processgrupp SIGTERM, sedan SIGKILL efter 5
sekunder.

De nätter då klockan ställs om följer jobben Debians cron-regel. Ett jobb med `*` i början av minut- eller timfältet
(även `*/N`), `@hourly` eller `@every` följer förfluten tid: på hösten körs det i båda genomgångarna av den upprepade
timmen, och på våren kommer den överhoppade timmen inte. Varje annat jobb kör var och en av sina tider en gång: en tid
i den upprepade timmen körs en gång, och en tid i den överhoppade timmen körs direkt efter omställningen.

Varje inloggat konto, även en `viewer`, ser jobbens kommandon och utdata från deras körningar. Skriv inte lösenord eller
token i ett kommando: låt det läsa dem från en fil under `<data>/etc` som bara root läser (`chmod 600`).

### Inbyggda jobb

| Jobb | När | Vad det gör |
|---|---|---|
| Underhåll | dagligen 03:30 | tar bort det som inget har ändrat på 10 dagar från `tmp/` i datamapp; roterar `log/audit.log` över 10 MB |
| Töm papperskorgen | dagligen 03:45 | tar bort det som flyttades till `trash/` i datamapp för mer än 7 dagar sedan (till exempel ett borttaget kontos hemmapp) |
| Uppdatering av verktygskedjekatalogen | dagligen 04:15 | hämtar den signerade katalogen för verktygskedjor |
| Rotera nginx loggar | varje timme, minut 7 | döper om `nginx-access.log` eller `nginx-error.log` till `.1` när den är över 20 MB (fem gamla filer sparas) och säger åt nginx att öppna sina loggar igen |

En admin kan ändra ett inbyggt jobbs schema, tidsgräns, policy och avisering, och stänga av det. Dess namn och
kommando förblir desamma.

### Operationer

Installationer, miljöjobb, flyttar av data och att slå på en modul körs som operationer. Listan visar de senaste 50,
nyaste först, med förlopp och logg. Operationer och deras loggar sparas i 30 dagar. En operation som pågick när
paketet stoppades visas som `interrupted`. En developer avbryter sina egna operationer; en admin avbryter vilken som
helst.

## Säkerhetskopior

Sidan **Säkerhetskopior** (admin) anger vad som säkerhetskopieras, när, vart kopiorna går och hur många som sparas.
**Säkerhetskopiera nu** kör en säkerhetskopiering när som helst. På en ny installation är schemalagda
säkerhetskopieringar av; när **Schemalagda säkerhetskopieringar** är på körs en säkerhetskopiering dagligen som
standard (det inbyggda cron-jobbet `backup`). Den behåller den senaste körningen för var och en av de senaste 7
dagarna, 4 veckorna och 6 månaderna, och alltid den senaste lyckade körningen. En säkerhetskopiering, verifiering,
återställning eller borttagning körs åt gången.

Två körningar samma dag räknas som en dag: när den nyare är klar tas dagens tidigare körning bort. En
**Säkerhetskopiera nu** på eftermiddagen ersätter därför den morgonens schemalagda körning; kopiera en körning någon
annanstans först när morgonens tillstånd spelar roll.

### Vad en säkerhetskopia innehåller

En körning är en mapp `<data>/backups/<id>/` med en `manifest.json` som listar varje fil med dess sha256:

| Del | Vad |
|---|---|
| inställningar | `etc/`: inställningar, konton, TOTP-hemligheter, TLS-nyckeln, nycklarna för säkerhetskopiering |
| Git | Forgejos dump: repositoryn, wikis, LFS-objekt, bilagor och dess databas |
| SVN, buckets | en kopia av varje repository, gjord inkrementellt: en revision som redan kopierats kopieras inte igen |
| VS Code-inställningar | varje kontos inställningar för VS Code, tangentbordsgenvägar, snippets och listan över dess tillägg (inte tilläggens filer: vyn Extensions installerar dem igen) |
| miljöer | miljöerna från Verktygskedjor (av som standard: de kan skapas igen) |
| projekt | varje projektmapp med sin Git-historik och de filer som inte är incheckade än, utan `node_modules` |
| HOME-mappar | varje kontos HOME-mapp, utan cacheminnen och AI-verktygens egna installationer (deras Installera-knapp lägger tillbaka dem) |
| App Builder | varje apps inställningar och historiken över dess byggen; ett bygge gör appens filer igen |
| paketrepository | de publicerade paketen, deras ikoner och indexet som App Center läser |

De här fyra delarna finns i varje säkerhetskopia, oavsett vad som är markerat på sidan. En mapp som inte har ändrats
sedan föregående säkerhetskopia länkas till den kopians exemplar och tar ingen plats.

Körningen blir synlig först när varje del är skriven och kontrollerad; ett fel eller en full volym tar bort den
ofullbordade mappen och lämnar tidigare körningar som de var. **Verifiera** läser tillbaka en körning helt: varje
arkivs sha256, `svnadmin verify` för varje revision, `git fsck` för varje repository och en integritetskontroll av
Forgejos databas.

### Mål

Varje körning kopieras till varje mål på sidan:

- **Lokal mapp** på den här NAS:en: körningen som den är, med oförändrade filer länkade till den föregående kopian, så
  att varje kopia bara kostar det som ändrats. Inte krypterad. På samma diskar som datan skyddar den mot misstag, inte
  mot en trasig volym.
- **rsync** (`user@host:path`) via SSH. **Logga in med paketets nyckel för säkerhetskopiering**: sidan visar den
  publika nyckel som ska läggas till i den andra maskinens `authorized_keys`.
- **rclone** (`remote:path`, en remote från `<data>/etc/rclone.conf`): molnlagring och allt som rclone når.

En kopia som lämnar NAS:en (rsync, rclone) måste vara krypterad: slå på **Kryptera kopior som lämnar NAS:en** och
**Skapa nyckeln**. Kopiorna krypteras med age till dess publika halva; **den hemliga halvan visas en gång** och bvsd
sparar den inte. Utan den kan ingen NAS, inte heller den här, återställa en krypterad kopia: förvara den någon
annanstans än på den här NAS:en. En ny nyckel krypterar körningarna från och med då; äldre kopior behöver den gamla
hemliga nyckeln.

Ett mål som misslyckas anges i körningens resultat; själva körningen förblir god.

`rclone.conf` innehåller fjärrmålens inloggningsuppgifter. Innan en kopia eller ett **Test** använder den gör bvsd
den (och säkerhetskopians nyckel) läsbar bara för root (läge 600) om den inte är det, och jobbets logg säger det.

### Återställa

**Återställ** på en körning lägger tillbaka antingen allt, ett repository (ett SVN-repository, en bucket eller ett
Git-repository) eller en projektmapp:

- Ingenting ersätts innan det har kontrollerats: varje arkiv mot sin sha256, varje SVN-kopia med `svnadmin verify`. En
  kopia som inte klarar sig stoppar återställningen innan något i den aktiva datan ändras.
- Den aktiva data som ersätts flyttas till `<data>/trash` i 7 dagar, så att även en återställning kan ångras.
- **Ett repository** eller **en projektmapp** läggs tillbaka medan modulerna fortsätter att köras. En projektmapp som
  tagits bort av misstag kommer tillbaka med sin historik och de filer som inte är incheckade än.
- **Allt** stoppar modulerna, byter ut datan och startar om bvsd med de återställda inställningarna: varje session
  avslutas, och kontona och lösenorden är de från säkerhetskopian. En projekt- eller HOME-mapp som skapades efter
  säkerhetskopian finns kvar.

## Aviseringar

bvsd skriver varje avisering till QTS systemloggar. Den kan också skicka dem till chatt- och e-posttjänster via
shoutrrr-URL:er (Telegram, Discord, Slack, e-post, en allmän webhook med flera).

| Avisering | När | Reglage för URL:erna |
|---|---|---|
| jobbfel | en cron-körning av ett jobb med avisering vid fel misslyckades eller överskred tidsgränsen; en operation misslyckades | `notify.on_job_failure` |
| säkerhetskopia | resultatet av varje säkerhetskopiering, verifiering och återställning, även de lyckade; en schemalagd säkerhetskopiering som inte kunde starta | `notify.on_backup` |
| omstartsslinga | en process började starta om i en slinga | `notify.on_crashloop` |
| certifikat | ett uppladdat certifikat har 30 dagar eller färre kvar; nginx föll tillbaka på det självsignerade certifikatet; ett nytt självsignerat certifikat skapades | `notify.on_cert_expiry` |
| system | inställningar som avvisades vid start, en ofullbordad flytt av data hittades, kvarlämnade processer avslutades, konfigurationen kunde inte skrivas | skickas alltid |

- Reglagen avgör bara vad som går till URL:erna. Systemloggarna får varje avisering.
- Samma avisering går ut högst en gång per 10 minuter. Nästa efter det säger hur många som hölls tillbaka.
- Varje URL får sitt eget `shoutrrr send` med en gräns på 10 sekunder. Ett fel loggas bara med URL:ens schema,
  eftersom resten av en URL innehåller dess token.

URL:erna och reglagen finns under **Aviseringar** på sidan System; reglagen är på som standard. En admin ändrar dem
där. Andra konton ser reglagen och bara schemat för varje URL, eftersom resten av en URL innehåller dess token.
NAS-admin kan också ställa in dem via CLI-socketen:

```bash
/usr/bin/bucketvs/bin/curl --unix-socket /usr/bin/bucketvs/var/run/bvsd-cli.sock \
  -X PUT -H 'Content-Type: application/json' \
  -d '{"notify":{"shoutrrr_urls":["telegram://<token>@telegram?chats=<chat id>"]}}' \
  http://bvsd/api/v1/settings
```

## Loggar och supportpaketet

Varje logg är `log/<name>.log` i datamapp. Loggarna från bvsd och från varje process den övervakar roteras vid 20 MB,
och fem gamla filer sparas. `nginx-access.log` och `nginx-error.log` har samma gränser, som kontrolleras vid varje
start av bvsd och varje timme av jobbet ”Rotera nginx loggar”, så en av dem kan gå över 20 MB med upp till en timmes
trafik. Jobbet ”Underhåll” roterar `audit.log` när den är över 10 MB och sparar tre gamla filer. Sidan Loggar (admin)
visar de sista raderna i valfri logg, filtrerar dem och följer nya rader när de kommer:

| Logg | Vad som skriver den |
|---|---|
| `bvsd` | bvsd själv: starter, stopp, tillämpade inställningar, problem |
| `nginx` | nginx egen utdata |
| `nginx-access`, `nginx-error` | varje begäran, och nginx fel |
| `audit` | varje begäran på CLI-socketen |
| en per modulprocess | varje moduls program |

Sidan System visar versionen, plattformen, tidszonen och varje process som bvsd övervakar. ”Ladda ner supportpaketet”
(admin) skapar ett arkiv för en felrapport:

- inställningarna med SMTP-lösenordet och varje shoutrrr-URL maskerade;
- den genererade `nginx.conf`, certifikatets uppgifter utan dess nyckel, volymerna;
- tillståndet för varje modul, process och nylig operation;
- de sista 2000 raderna i varje logg, med varje frågesträng i dem ersatt av `?(query removed)`.

Det innehåller aldrig lösenord, sessioner, token eller nycklar.

## Uppdateringar

bvsd läser `https://pub.qnaputilities.com/bucketvs/latest.json` vid start och var 24:e timme. När den anger en nyare
version visar sidan System den, med länken som flödet ger. bvsd rapporterar bara den nya versionen: den laddar aldrig
ner eller installerar ett paket. En misslyckad kontroll ändrar ingenting i panelen.

### Installera en ny version

Installera det nya paketet över det gamla, från App Center eller med **Installera manuellt**. Installationen stoppar
bvsd, ersätter programfilerna och startar den igen; datamapp, inställningarna, kontona och varje repository finns kvar,
liksom panelens sessioner. Redigerarinstanserna stoppas med bvsd, så redigerarnas öppna terminaler avslutas; en instans
startar igen när dess konto öppnar redigeraren.

**Från en version som använde portarna 6050, 6051 och 6052.** Tidigare byggen lyssnade på 6050 (HTTP), 6051 (HTTPS)
och 6052 (Git via SSH). Den nya versionens första start flyttar var och en av dem till 9950, 9951 och 9952 och säger
det i en avisering; en port som du själv valt behålls. Ändra det som anger de gamla portarna: bokmärken, en
Plesk-proxy till 6050, och git-remotes som `ssh://git@<NAS>:6052/…` (`git remote set-url`).

### Ta bort, installera om och ett skadat paket

Ditt arbete finns kvar när paketet tas bort, installeras om eller skadas. Allt du skapar ligger i datamappen: konton och
inställningar, Git- och SVN-repositoryn, buckets, projektmappar, HOME-mappar, VS Code-inställningar och tillägg, appar
i App Builder, miljöer, paketrepositoryt och säkerhetskopiorna. Installationsmappen (`<volym>/.qpkg/bucketvs`)
innehåller bara programmen och en fil som pekar ut datamappen.

- **Ta bort, installera sedan igen.** När paketet tas bort raderas installationsmappen, medan datamappen och
  `/etc/config/bucketvs-data-root`, filen som pekar ut den, finns kvar. Nästa installation läser den filen och startar
  på samma datamapp: samma konton och lösenord, samma projekt och repositoryn, inloggade sessioner inräknade.
- **Installera över det installerade paketet.** Samma version eller en nyare ersätter programfilerna; datamappen rörs
  inte.
- **Ett skadat paket.** När installationsmappen är skadad (ett program saknas, mappen togs bort för hand), installera
  paketet igen från App Center eller med **Installera manuellt**. Installationen hittar datamappen på samma sätt. En
  bvsd som fortfarande körs från borttagna filer stoppas vid starten, och den installerade startar.
- **Vad som raderar datan.** Bara att ta bort själva datamappen. För att börja tomt med avsikt tar du bort paketet,
  tar bort datamappen och installerar sedan: första starten skapar en ny datamapp, som [Var datamapp
  börjar](#var-datamappen-börjar) beskriver.

En disk som går sönder är en annan sak: datamappen ligger på NAS:ens egna diskar. Spara säkerhetskopior på en annan
maskin ([Säkerhetskopior](#säkerhetskopior)); varje säkerhetskopia innehåller dina projektmappar, HOME-mappar,
inställningarna i App Builder och paketrepositoryt.

## Kommandot bvs

`bvs` är paketets kommandorad, i `/usr/bin/bucketvs/bin`. Den finns i `PATH` för varje process som bvsd startar,
cron-jobb inräknade. Medan paketet körs är `/usr/bin/bvs` en länk till den, så i en SSH-session på NAS:en anropar du
den också med namn; när paketet stoppas tas länken bort.

Varje kommando som pratar med bvsd via dess CLI-socket kräver root, eftersom socketen bara tillhör root: `user`,
`jobs` och, medan bvsd körs, `tc install`, `tc remove` och `env create`, `clone`, `export` och `delete`. `env shell`,
`env run` och `qbuild` kräver också root: de startar `bvs-chroot`. Som en annan användare stannar ett kommando som
behöver socketen med ”bvsd's CLI socket … is open to root only: run bvs as root”.

```text
bvs env list
bvs env create <name> --from <rootfs-id> [--package <name>]...
bvs env shell <name>
bvs env run <name> -- <command> [<arg>...]
bvs env clone <name> <new-name>
bvs env export <name>
bvs env delete <name>
bvs tc list
bvs tc install <id>
bvs tc remove <id>
bvs use <id>
bvs jobs
bvs user list
bvs user password <name>
bvs user totp-reset <name>
bvs guide [--path] [en|pl|de|fr|it|nl|sv|ja|zh-TW]
bvs qbuild [--env <name>] [<qbuild argument>...]
bvs kernel profile [--json]
bvs kernel sources
bvs kernel prepare [--source <id>] [--env <name>] [--option NAME=VALUE]... [--full]
bvs kernel make [--project <folder> | --dir <tree directory>] [--build-only] [<target>...]
bvs kernel check <file.ko | module>
bvs kernel load <module>
bvs kernel unload <module>
```

- Medan bvsd körs går installationer och miljöjobb till bvsd via dess CLI-socket, så att panelen visar dem, och `bvs`
  följer dem tills de är klara. Utan bvsd körs de i själva `bvs`-processen; `--local` före kommandot gör det med
  avsikt.
- `bvs jobs` och `user`-kommandona behöver bvsd.
- `bvs guide` öppnar den här handboken med paketets `less` i en terminal, och skriver annars, eller med `--path`, ut
  sökvägen till dess fil. Utan språk följer den den första som är satt av `LC_ALL`, `LC_MESSAGES` och `LANG`:
  `de_DE.UTF-8` öppnar den tyska handboken, `zh_TW` och `zh_HK` den traditionellt kinesiska, och ett språk som
  handboken inte är skriven på (`C`, `zh_CN`) den engelska.

## Filer och mappar

| Sökväg | Vad |
|---|---|
| `/usr/bin/bucketvs` | paketets program (en länk till dess installationsmapp) |
| `/usr/bin/bucketvs/etc/data-root` | sökvägen till datamapp |
| `/usr/bin/bucketvs/var/run/bvsd.sock` | panelens API-socket (nginx använder den) |
| `/usr/bin/bucketvs/var/run/bvsd-cli.sock` | socketen för kommandot `bvs`, bara root |
| `<datamapp>/etc/` | inställningar, konton, sessioner, token, certifikaten, den genererade `nginx.conf` (hemligheter med läge 600) |
| `<datamapp>/log/` | loggarna |
| `<datamapp>/tmp/` | tillfälliga filer för varje process |
| `<datamapp>/home/<användare>/` | hemmappen för varje konto |
| `<datamapp>/jobs/` | operationer, cron-jobb och deras körningar, med loggar |
| `<datamapp>/toolchains/` | nedladdningscachen, installerade verktygskedjor och körmiljöer, exporter |
| `<datamapp>/envs/` | miljöer |
| `<datamapp>/projects/` | arbetsytor, synliga som `/projects` inuti miljöer |
| `<datamapp>/trash/` | borttagna objekt, sparas i 7 dagar |

Modulerna lägger till egna mappar; deras avsnitt anger dem.
