Herstel installatie-instructies en hard deploy-script (v0.2.03 beta)
De installatiestappen in de README waren niet uitvoerbaar en het deploy-script kon stilzwijgend werk vernietigen. README: - `python manage.py migrate` liep vast op `RuntimeError: DJANGO_SECRET_KEY ontbreekt`. DEBUG staat standaard uit en dan is die sleutel verplicht; de instructies noemden `DJANGO_DEBUG` nergens. Nu toegevoegd, met uitleg. - `createsuperuser` stond als "optioneel, voor /admin/". Dat klopt niet: de hele API staat op `IsAuthenticated`, dus zonder account kom je de app helemaal niet in. Nu gemarkeerd als verplichte stap. - Stap voor een virtual environment toegevoegd (pip installeerde anders in de systeem-Python, wat op recente distributies afketst op PEP 668). - Node-eis vermeld: Vite 8 vereist 20.19+ of 22.12+. - Verouderde beschrijvingen bijgewerkt: de tabs van het roosterscherm (Week/Genereren/Instellingen in plaats van Weekrooster/Conflicten/ Schooljaar/Instellingen), Groepsindeling is een eigen scherm en geen tab, en er zijn twaalf modules in plaats van "twee voorbeeldmodules". DEPLOY.md: - `git clone .../Roostersoftware.git` + `cd Roostersoftware` gebruikte de verkeerde repo-naam; dat is `roosterwijs`. - CSRF-origin en FRONTEND_BASE_URL stonden als http-voorbeeld; achter TLS moet dat https zijn. - Rechtgezet: `DJANGO_CSRF_TRUSTED_ORIGINS` blokkeert het inloggen in de app niet (DRF-views zijn `csrf_exempt`), maar wel de Django-admin. - Vermeld dat er nergens automatisch een account wordt aangemaakt. scripts/deploy.sh: - Stopt nu als `.env` ontbreekt; anders start de stack met lege variabelen en faalt de backend met een onduidelijke fout. - Stopt bij lokale wijzigingen in plaats van ze met `git reset --hard` weg te gooien; bewust overschrijven kan met `--force`. - Controleert vooraf of Docker en de compose-plugin er zijn. - Toont welke commits erbij komen (oud -> nieuw) in plaats van alleen de nieuwe HEAD. - Controleert na afloop of de backend antwoordt en of er een actief account bestaat, met het createsuperuser-commando als dat er niet is. frontend/Dockerfile: - Bouwt op node:22-alpine in plaats van node:20-alpine, gelijk aan de CI en ruim binnen de Node-eis van Vite 8. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FAQ4Np13v8fwbTtKHKnwDz
This commit is contained in:
parent
1865de948e
commit
500cf6c558
7 changed files with 164 additions and 40 deletions
36
DEPLOY.md
36
DEPLOY.md
|
|
@ -22,9 +22,18 @@ erboven (meestal een SSH-/sleutelprobleem).
|
||||||
./scripts/deploy.sh
|
./scripts/deploy.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Dit haalt de laatste code op (`git reset --hard origin/<branch>`), herbouwt de
|
Dit controleert eerst of Docker en `.env` aanwezig zijn, haalt dan de laatste
|
||||||
containers (incl. migraties via de entrypoint) en controleert of er een nieuwe
|
code op (`git reset --hard origin/<branch>`), herbouwt de containers (incl.
|
||||||
frontend-bundel staat.
|
migraties via de entrypoint) en controleert daarna of de frontend-bundel er
|
||||||
|
staat, of de backend antwoordt en of er een actief account is om mee in te
|
||||||
|
loggen.
|
||||||
|
|
||||||
|
Staan er **lokale wijzigingen** in de map op de server, dan stopt het script:
|
||||||
|
`git reset --hard` zou die weggooien. Zet ze eerst veilig, of forceer bewust:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/deploy.sh --force
|
||||||
|
```
|
||||||
|
|
||||||
Nieuwe **modules** verschijnen daarna pas in de app nadat je ze aanzet via
|
Nieuwe **modules** verschijnen daarna pas in de app nadat je ze aanzet via
|
||||||
**⚙ → Modulebeheer**.
|
**⚙ → Modulebeheer**.
|
||||||
|
|
@ -45,7 +54,7 @@ EMAIL_HOST_USER=postvak@jouwschool.nl
|
||||||
EMAIL_HOST_PASSWORD=...
|
EMAIL_HOST_PASSWORD=...
|
||||||
EMAIL_USE_TLS=1
|
EMAIL_USE_TLS=1
|
||||||
DEFAULT_FROM_EMAIL=Roosterwijs <noreply@jouwschool.nl>
|
DEFAULT_FROM_EMAIL=Roosterwijs <noreply@jouwschool.nl>
|
||||||
FRONTEND_BASE_URL=http://rooster-test.example.nl:8080
|
FRONTEND_BASE_URL=https://rooster.example.nl
|
||||||
```
|
```
|
||||||
|
|
||||||
`FRONTEND_BASE_URL` bepaalt de basis van de resetlink in de e-mail (zonder
|
`FRONTEND_BASE_URL` bepaalt de basis van de resetlink in de e-mail (zonder
|
||||||
|
|
@ -76,8 +85,8 @@ Je hoeft op de server **niets** te installeren behalve Docker zelf (met de
|
||||||
```
|
```
|
||||||
2. Haal de code op:
|
2. Haal de code op:
|
||||||
```bash
|
```bash
|
||||||
git clone <jouw-forgejo-url>/Roostersoftware.git
|
git clone <jouw-forgejo-url>/roosterwijs.git
|
||||||
cd Roostersoftware
|
cd roosterwijs
|
||||||
```
|
```
|
||||||
3. Maak het `.env`-bestand aan vanuit het voorbeeld en vul echte waarden in:
|
3. Maak het `.env`-bestand aan vanuit het voorbeeld en vul echte waarden in:
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -88,7 +97,8 @@ Je hoeft op de server **niets** te installeren behalve Docker zelf (met de
|
||||||
- `DJANGO_SECRET_KEY` — genereer met
|
- `DJANGO_SECRET_KEY` — genereer met
|
||||||
`python3 -c "import secrets; print(secrets.token_urlsafe(50))"`
|
`python3 -c "import secrets; print(secrets.token_urlsafe(50))"`
|
||||||
- `DJANGO_ALLOWED_HOSTS` — de hostnaam/IP van de test-server
|
- `DJANGO_ALLOWED_HOSTS` — de hostnaam/IP van de test-server
|
||||||
- `DJANGO_CSRF_TRUSTED_ORIGINS` — `http://<host>:8080` (of je echte URL)
|
- `DJANGO_CSRF_TRUSTED_ORIGINS` — exact de origin die de browser gebruikt,
|
||||||
|
dus `https://<host>` achter TLS (of `http://<host>:8080` zonder TLS)
|
||||||
- `POSTGRES_PASSWORD` — een sterk wachtwoord
|
- `POSTGRES_PASSWORD` — een sterk wachtwoord
|
||||||
|
|
||||||
`.env` staat in `.gitignore` en komt dus **niet** in git — dat hoort zo.
|
`.env` staat in `.gitignore` en komt dus **niet** in git — dat hoort zo.
|
||||||
|
|
@ -116,7 +126,10 @@ pas hem daar aan als die poort bezet is.)
|
||||||
docker compose exec backend python manage.py createsuperuser
|
docker compose exec backend python manage.py createsuperuser
|
||||||
```
|
```
|
||||||
|
|
||||||
Daarna kun je inloggen op `http://<server-host>:8080/admin/`.
|
Dit account heb je **hoe dan ook** nodig: de hele API staat op
|
||||||
|
`IsAuthenticated`, dus zonder gebruiker kom je ook de app zelf niet in — niet
|
||||||
|
alleen `/admin/`. Zonder dit commando wordt er nergens automatisch een account
|
||||||
|
aangemaakt; `entrypoint.sh` draait alleen migraties en `collectstatic`.
|
||||||
|
|
||||||
## Updaten na nieuwe code
|
## Updaten na nieuwe code
|
||||||
|
|
||||||
|
|
@ -164,8 +177,11 @@ zonder tussenkomst van Django).
|
||||||
als je een eigen nginx/Apache ervoor hebt.
|
als je een eigen nginx/Apache ervoor hebt.
|
||||||
2. **`DJANGO_CSRF_TRUSTED_ORIGINS` moet de https-origin zijn**, exact zoals de
|
2. **`DJANGO_CSRF_TRUSTED_ORIGINS` moet de https-origin zijn**, exact zoals de
|
||||||
browser hem gebruikt (bv. `https://rooster.example.nl`, zonder poort op 443).
|
browser hem gebruikt (bv. `https://rooster.example.nl`, zonder poort op 443).
|
||||||
Staat hier nog een `http://`-adres, dan geeft elke POST — inclusief het
|
Dit geldt voor de **Django-admin** en andere gewone Django-formulieren: staat
|
||||||
inloggen — een CSRF-fout (HTTP 403).
|
hier een `http://`-adres, dan weigert `/admin/` je aanmelding met een
|
||||||
|
CSRF-fout (HTTP 403). Het inloggen in de app zelf loopt hier níet op stuk —
|
||||||
|
DRF-views zijn `csrf_exempt` en `SessionAuthentication` controleert CSRF pas
|
||||||
|
als er al een sessie is.
|
||||||
3. **`DJANGO_ALLOWED_HOSTS` moet de publieke hostnaam bevatten**, anders volgt
|
3. **`DJANGO_ALLOWED_HOSTS` moet de publieke hostnaam bevatten**, anders volgt
|
||||||
een 400 Bad Request.
|
een 400 Bad Request.
|
||||||
|
|
||||||
|
|
|
||||||
52
README.md
52
README.md
|
|
@ -11,10 +11,11 @@ Fase 3 (afwezigheid, uitzonderingen, effectief weekrooster) en Fase 4
|
||||||
|
|
||||||
Het Rooster-scherm is een **weekweergave met drag-and-drop** (muis én touch) en
|
Het Rooster-scherm is een **weekweergave met drag-and-drop** (muis én touch) en
|
||||||
een **touch-vriendelijk** ontwerp; vrije dagen, afwezigheid en uitzonderingen
|
een **touch-vriendelijk** ontwerp; vrije dagen, afwezigheid en uitzonderingen
|
||||||
worden automatisch verwerkt. Het Rooster heeft tabs **Weekrooster / Conflicten /
|
worden automatisch verwerkt. De Roostermaker heeft tabs **Week / Genereren /
|
||||||
Schooljaar / Instellingen** (tijdsloten, activiteiten en locaties beheer je daar,
|
Instellingen**: onder Instellingen beheer je schooljaar + kalender, tijdvakken,
|
||||||
en het schooljaar + de kalender voer je in onder de Schooljaar-tab, zodat het menu
|
vakken, lokalen, locaties en vormgeving; onder Genereren zitten de Vak-wizard en
|
||||||
rustiger is). De zijbalk groepeert items onder inklapbare submenu's (Personen,
|
het Auto-rooster. Conflicten verschijnen als melding boven het weekrooster, niet
|
||||||
|
als aparte tab. De zijbalk groepeert items onder inklapbare submenu's (Personen,
|
||||||
Groepen) en heeft onderaan een subtiel **Instellingen**-blok met Gebruikers en
|
Groepen) en heeft onderaan een subtiel **Instellingen**-blok met Gebruikers en
|
||||||
Modulebeheer.
|
Modulebeheer.
|
||||||
|
|
||||||
|
|
@ -22,9 +23,10 @@ Er zijn twee rooster-schermen: **Rooster** (alleen-lezen weergave, om te bekijke
|
||||||
en af te drukken) en **Roostermaker** (de aanpasser met drag-and-drop, tabs en
|
en af te drukken) en **Roostermaker** (de aanpasser met drag-and-drop, tabs en
|
||||||
conflictdetectie). In de Roostermaker open je een blok met een **klik** om het te
|
conflictdetectie). In de Roostermaker open je een blok met een **klik** om het te
|
||||||
bewerken (vak, locatie, doelgroep, begeleiders, opmerking) of te **kopiëren** naar
|
bewerken (vak, locatie, doelgroep, begeleiders, opmerking) of te **kopiëren** naar
|
||||||
andere tijden/dagen. De tab **Indeling** verdeelt een hoofdgroep (of leerplein)
|
andere tijden/dagen. Het aparte scherm **Groepsindeling** (zijbalk → Organisatie)
|
||||||
kolomsgewijs in subgroepen, met per subgroep de vakken en de verantwoordelijke(n),
|
verdeelt een hoofdgroep of leerplein kolomsgewijs in subgroepen, met per subgroep
|
||||||
en je kunt er direct subgroepen toevoegen. Beide schermen hebben een **scope-filter** (alles / per klas /
|
de vakken en de verantwoordelijke(n), en je kunt er direct subgroepen toevoegen.
|
||||||
|
Beide roosterschermen hebben een **scope-filter** (alles / per klas /
|
||||||
per leerplein / per leerling / per personeel); de module **Printen/Exporteren**
|
per leerplein / per leerling / per personeel); de module **Printen/Exporteren**
|
||||||
voegt — als die aanstaat — een subtiele **Afdrukken**-knop toe die het (gefilterde)
|
voegt — als die aanstaat — een subtiele **Afdrukken**-knop toe die het (gefilterde)
|
||||||
weekrooster printvriendelijk afdrukt of als PDF bewaart.
|
weekrooster printvriendelijk afdrukt of als PDF bewaart.
|
||||||
|
|
@ -52,11 +54,14 @@ geboortedatum vast.
|
||||||
- **Backend** (`backend/`) — Django + Django REST Framework.
|
- **Backend** (`backend/`) — Django + Django REST Framework.
|
||||||
- `plugins/` — het plugin-framework: een moduleregister, opslag van de
|
- `plugins/` — het plugin-framework: een moduleregister, opslag van de
|
||||||
aan/uit-status per module en een beheer-API.
|
aan/uit-status per module en een beheer-API.
|
||||||
- `core/` — de kern (altijd actief). **Fase 1**: modellen Persoon, Groep en
|
- `core/` — de kern (altijd actief): personen, groepen, subgroepen,
|
||||||
Subgroep met een volledige CRUD-API. Roosterblokken en kalender volgen in
|
functies, schooljaar + kalender, tijdvakken, activiteiten, locaties,
|
||||||
fase 2.
|
lokalen, roosterblokken en conflictdetectie, elk met een CRUD-API.
|
||||||
- `modules/printing/` en `modules/accounts/` — twee voorbeeldmodules die
|
- `modules/` — twaalf modules die zich bij opstarten aanmelden bij het
|
||||||
zich bij opstarten aanmelden bij het register.
|
register: `printing`, `accounts`, `leerplein`, `stage`, `uren`,
|
||||||
|
`blokwizard`, `personenwizard`, `autorooster`, `huisstijl`,
|
||||||
|
`importexport`, `vervanging` en `portal`. De volledige lijst staat in
|
||||||
|
`MODULE_APPS` in `backend/config/settings.py`.
|
||||||
- **Frontend** (`frontend/`) — React (Vite). Zijbalk met Roosterwijs-logo die
|
- **Frontend** (`frontend/`) — React (Vite). Zijbalk met Roosterwijs-logo die
|
||||||
alleen menu's toont van ingeschakelde modules, beheerschermen voor
|
alleen menu's toont van ingeschakelde modules, beheerschermen voor
|
||||||
**Personen**, **Groepen** en **Subgroepen**, en een scherm **Modulebeheer**.
|
**Personen**, **Groepen** en **Subgroepen**, en een scherm **Modulebeheer**.
|
||||||
|
|
@ -74,18 +79,34 @@ geboortedatum vast.
|
||||||
Een nieuwe module toevoegen = nieuwe app maken, één regel in
|
Een nieuwe module toevoegen = nieuwe app maken, één regel in
|
||||||
`MODULE_APPS` (in `backend/config/settings.py`), klaar.
|
`MODULE_APPS` (in `backend/config/settings.py`), klaar.
|
||||||
|
|
||||||
## Starten
|
## Starten (lokaal ontwikkelen)
|
||||||
|
|
||||||
|
> Voor een test- of productieserver gelden **andere** stappen: zie `DEPLOY.md`.
|
||||||
|
> Daar draait alles in Docker en komt de configuratie uit `.env`.
|
||||||
|
|
||||||
### Backend (Django, poort 8000)
|
### Backend (Django, poort 8000)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
|
python3 -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Zonder DJANGO_DEBUG=1 weigert Django te starten: buiten debug is
|
||||||
|
# DJANGO_SECRET_KEY verplicht. Met debug aan valt hij terug op een dev-sleutel.
|
||||||
|
export DJANGO_DEBUG=1 # Windows: $env:DJANGO_DEBUG="1"
|
||||||
|
|
||||||
python manage.py migrate
|
python manage.py migrate
|
||||||
python manage.py createsuperuser # optioneel, voor /admin/
|
python manage.py createsuperuser # VERPLICHT, zie hieronder
|
||||||
python manage.py runserver
|
python manage.py runserver
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**`createsuperuser` is geen optionele stap.** De hele API staat op
|
||||||
|
`IsAuthenticated` en de frontend toont eerst een inlogscherm; zonder account kom
|
||||||
|
je nergens binnen — ook niet in de app zelf, niet alleen in `/admin/`.
|
||||||
|
|
||||||
|
Zonder `POSTGRES_DB` in de omgeving gebruikt de backend automatisch SQLite in
|
||||||
|
`backend/db.sqlite3`. `DEPLOY.md` zet PostgreSQL in via `.env`.
|
||||||
|
|
||||||
API-eindpunten:
|
API-eindpunten:
|
||||||
- `GET /api/modules/` — alle modules met status.
|
- `GET /api/modules/` — alle modules met status.
|
||||||
- `POST /api/modules/<key>/state/` — body `{"enabled": true|false}`.
|
- `POST /api/modules/<key>/state/` — body `{"enabled": true|false}`.
|
||||||
|
|
@ -111,6 +132,9 @@ API-eindpunten:
|
||||||
|
|
||||||
### Frontend (React, poort 5173)
|
### Frontend (React, poort 5173)
|
||||||
|
|
||||||
|
Vereist **Node 20.19+ of 22.12+** — Vite 8 weigert oudere versies.
|
||||||
|
Controleer met `node -v`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd frontend
|
cd frontend
|
||||||
npm install
|
npm install
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
# Frontend in twee fases:
|
# Frontend in twee fases:
|
||||||
# 1) Node bouwt de React-app tot statische bestanden.
|
# 1) Node bouwt de React-app tot statische bestanden (Node 22: Vite 8 eist
|
||||||
|
# ^20.19 of >=22.12, en de CI bouwt ook op 22 — zelfde versie overal).
|
||||||
# 2) Nginx serveert die bestanden en proxyt /api en /admin naar de backend.
|
# 2) Nginx serveert die bestanden en proxyt /api en /admin naar de backend.
|
||||||
|
|
||||||
# --- Fase 1: build --------------------------------------------------------
|
# --- Fase 1: build --------------------------------------------------------
|
||||||
FROM node:20-alpine AS build
|
FROM node:22-alpine AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
# npm ci (reproduceerbaar) zodra er een package-lock.json in git staat;
|
# npm ci (reproduceerbaar) zodra er een package-lock.json in git staat;
|
||||||
|
|
|
||||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "roosterwijs-frontend",
|
"name": "roosterwijs-frontend",
|
||||||
"version": "0.2.2-beta",
|
"version": "0.2.3-beta",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "roosterwijs-frontend",
|
"name": "roosterwijs-frontend",
|
||||||
"version": "0.2.2-beta",
|
"version": "0.2.3-beta",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^18.3.1"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "roosterwijs-frontend",
|
"name": "roosterwijs-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.2-beta",
|
"version": "0.2.3-beta",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ button,a,input,select{transition:border-color .15s,background-color .15s,color .
|
||||||
.cog-btn{width:100%;min-height:38px;justify-content:flex-start;font-size:15px;padding:0}
|
.cog-btn{width:100%;min-height:38px;justify-content:flex-start;font-size:15px;padding:0}
|
||||||
.cog-btn::after{content:"Beheer en instellingen";margin-left:8px;font-size:13px}
|
.cog-btn::after{content:"Beheer en instellingen";margin-left:8px;font-size:13px}
|
||||||
.cog-dropdown{position:static;min-width:0;margin:4px 0 0;box-shadow:none}
|
.cog-dropdown{position:static;min-width:0;margin:4px 0 0;box-shadow:none}
|
||||||
.topbar::after{content:"v0.2.02 beta";order:4;margin:10px 8px 0;color:#98a2b3;font-size:10px}
|
.topbar::after{content:"v0.2.03 beta";order:4;margin:10px 8px 0;color:#98a2b3;font-size:10px}
|
||||||
.content{margin-left:var(--sidebar);width:calc(100% - var(--sidebar));max-width:1680px;padding:32px 38px 48px}
|
.content{margin-left:var(--sidebar);width:calc(100% - var(--sidebar));max-width:1680px;padding:32px 38px 48px}
|
||||||
.content-wide{padding:24px 28px 42px}
|
.content-wide{padding:24px 28px 42px}
|
||||||
h1{font-size:clamp(24px,2.4vw,30px);line-height:1.2;letter-spacing:-.025em;font-weight:750}
|
h1{font-size:clamp(24px,2.4vw,30px);line-height:1.2;letter-spacing:-.025em;font-weight:750}
|
||||||
|
|
|
||||||
103
scripts/deploy.sh
Normal file → Executable file
103
scripts/deploy.sh
Normal file → Executable file
|
|
@ -1,19 +1,102 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Op de test-server: haal de laatste code op en herbouw de containers.
|
# Op de test-server: haal de laatste code op en herbouw de containers.
|
||||||
# Gebruik: ./scripts/deploy.sh
|
#
|
||||||
|
# Gebruik: ./scripts/deploy.sh [--force]
|
||||||
|
# --force ook doorgaan als er lokale wijzigingen zijn
|
||||||
|
# (let op: die worden dan overschreven)
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
branch="$(git rev-parse --abbrev-ref HEAD)"
|
force=0
|
||||||
echo "Branch: $branch"
|
for arg in "${@:-}"; do
|
||||||
git fetch origin
|
case "$arg" in
|
||||||
# Forceer exact gelijk aan de remote (voorkomt 'already up to date'-verwarring).
|
"") ;;
|
||||||
git reset --hard "origin/$branch"
|
--force) force=1 ;;
|
||||||
echo "Nu op commit:"
|
*) echo "Onbekende optie: $arg" >&2; exit 2 ;;
|
||||||
git --no-pager log --oneline -1
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Vooraf controleren ---------------------------------------------------
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "FOUT: docker is niet geïnstalleerd op deze server." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! docker compose version >/dev/null 2>&1; then
|
||||||
|
echo "FOUT: 'docker compose' werkt niet (compose-plugin ontbreekt)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Zonder .env start de stack met lege variabelen: compose vult dan overal
|
||||||
|
# lege strings in, de backend ziet geen POSTGRES_DB (valt terug op SQlite in
|
||||||
|
# de container) en weigert te starten omdat DJANGO_SECRET_KEY ontbreekt.
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
echo "FOUT: .env ontbreekt in $(pwd)." >&2
|
||||||
|
echo " Maak hem aan met: cp .env.example .env && nano .env" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 'git reset --hard' hieronder gooit lokale aanpassingen weg — bijvoorbeeld een
|
||||||
|
# met de hand aangepaste nginx.conf. Daarom eerst waarschuwen.
|
||||||
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
|
echo "LET OP: er staan lokale wijzigingen in deze map:"
|
||||||
|
git --no-pager status --short | sed 's/^/ /'
|
||||||
|
if [ "$force" -ne 1 ]; then
|
||||||
|
echo
|
||||||
|
echo "Die gaan verloren bij het bijwerken. Zet ze eerst veilig, of draai:" >&2
|
||||||
|
echo " ./scripts/deploy.sh --force" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "--force opgegeven: deze wijzigingen worden overschreven."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Code bijwerken -------------------------------------------------------
|
||||||
|
branch="$(git rev-parse --abbrev-ref HEAD)"
|
||||||
|
oud="$(git rev-parse --short HEAD)"
|
||||||
|
echo "Branch: $branch (nu op $oud)"
|
||||||
|
|
||||||
|
git fetch origin
|
||||||
|
git reset --hard "origin/$branch"
|
||||||
|
nieuw="$(git rev-parse --short HEAD)"
|
||||||
|
|
||||||
|
if [ "$oud" = "$nieuw" ]; then
|
||||||
|
echo "Geen nieuwe commits; containers worden wel opnieuw gebouwd."
|
||||||
|
else
|
||||||
|
echo "Bijgewerkt: $oud -> $nieuw"
|
||||||
|
git --no-pager log --oneline "$oud..$nieuw" | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Bouwen en starten ----------------------------------------------------
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
|
|
||||||
echo "Controle: nieuwe frontend-bundel aanwezig?"
|
# --- Controleren ----------------------------------------------------------
|
||||||
docker compose exec -T nginx sh -c 'ls /usr/share/nginx/html/assets/*.js >/dev/null 2>&1 && echo " frontend OK" || echo " GEEN frontend-bundel gevonden"'
|
echo
|
||||||
|
echo "Controle: frontend-bundel aanwezig?"
|
||||||
|
if docker compose exec -T nginx sh -c 'ls /usr/share/nginx/html/assets/*.js >/dev/null 2>&1'; then
|
||||||
|
echo " frontend OK"
|
||||||
|
else
|
||||||
|
echo " GEEN frontend-bundel gevonden"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Controle: reageert de backend?"
|
||||||
|
docker compose exec -T backend python -c "
|
||||||
|
import urllib.request, urllib.error
|
||||||
|
try:
|
||||||
|
r = urllib.request.urlopen('http://127.0.0.1:8000/api/info/', timeout=5)
|
||||||
|
print(' backend OK (HTTP', r.status, ')')
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(' backend OK (HTTP', e.code, '- reageert)')
|
||||||
|
except Exception as e:
|
||||||
|
print(' GEEN antwoord van de backend:', e)
|
||||||
|
" || echo " Kon de backend niet bereiken — zie 'docker compose logs backend'."
|
||||||
|
|
||||||
|
echo "Controle: is er een gebruiker om mee in te loggen?"
|
||||||
|
docker compose exec -T backend python manage.py shell -c "
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
n = get_user_model().objects.filter(is_active=True).count()
|
||||||
|
print(' actieve gebruikers:', n)
|
||||||
|
if n == 0:
|
||||||
|
print(' LET OP: geen actief account. Maak er een met:')
|
||||||
|
print(' docker compose exec backend python manage.py createsuperuser')
|
||||||
|
" || echo " Kon de gebruikers niet tellen — zie 'docker compose logs backend'."
|
||||||
|
|
||||||
echo "Klaar."
|
echo "Klaar."
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue