Compare commits
6 Commits
c4785455eb
...
d8800daba3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8800daba3 | ||
|
|
5fd943db85 | ||
|
|
00db9182d9 | ||
|
|
3f52db35c2 | ||
|
|
16c1913e69 | ||
|
|
5490593b94 |
10
Dockerfile
10
Dockerfile
@@ -1,15 +1,15 @@
|
|||||||
FROM python:3.14-alpine
|
FROM python:3.14-alpine
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
|
|
||||||
COPY requirements.txt /src/
|
COPY requirements.txt /src/
|
||||||
COPY gunicorn.conf.py /src/
|
|
||||||
COPY ./src/ /src/
|
|
||||||
|
|
||||||
RUN pip install --upgrade pip && \
|
RUN pip install --upgrade pip && \
|
||||||
pip install --no-cache-dir -r requirements.txt
|
pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
EXPOSE 8000
|
COPY gunicorn.conf.py /src/
|
||||||
|
COPY ./src/ /src/
|
||||||
|
|
||||||
CMD ["gunicorn", "website.wsgi:application"]
|
CMD ["gunicorn", "website.wsgi:application"]
|
||||||
|
|
||||||
|
|||||||
14
Makefile
14
Makefile
@@ -1,20 +1,22 @@
|
|||||||
|
.SHELLFLAGS := -ec
|
||||||
|
|
||||||
prod:
|
prod:
|
||||||
docker compose down
|
docker compose down
|
||||||
docker compose --env-file .env -f ./compose.yaml -f ./.docker-compose-files/compose.prod.yaml up -d --build
|
docker compose --env-file .env -f ./compose.yaml -f ./.docker-compose-files/compose.prod.yaml up -d --build
|
||||||
docker exec quatsh-website-web-1 python manage.py collectstatic --noinput
|
docker compose exec web python manage.py collectstatic --noinput
|
||||||
docker exec quatsh-website-web-1 python manage.py check --deploy
|
docker compose exec web python manage.py check --deploy
|
||||||
docker exec quatsh-website-web-1 python manage.py migrate
|
docker compose exec web python manage.py migrate
|
||||||
|
|
||||||
dev:
|
dev:
|
||||||
docker compose down
|
docker compose down
|
||||||
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.dev.yaml up --build -d
|
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.dev.yaml up --build -d
|
||||||
docker exec quatsh-website-web-1 python manage.py collectstatic --noinput
|
docker compose exec web python manage.py collectstatic --noinput
|
||||||
docker exec -it quatsh-website-web-1 sh
|
docker compose exec -it web sh
|
||||||
|
|
||||||
dev_restart:
|
dev_restart:
|
||||||
docker compose down
|
docker compose down
|
||||||
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.dev.yaml up -d
|
docker compose -f ./compose.yaml -f ./.docker-compose-files/compose.dev.yaml up -d
|
||||||
docker exec -it quatsh-website-web-1 sh
|
docker compose exec -it web sh
|
||||||
|
|
||||||
dev_restart_with_logs:
|
dev_restart_with_logs:
|
||||||
docker compose down
|
docker compose down
|
||||||
|
|||||||
32
compose.yaml
32
compose.yaml
@@ -3,11 +3,11 @@ services:
|
|||||||
build: .
|
build: .
|
||||||
command: gunicorn website.wsgi:application
|
command: gunicorn website.wsgi:application
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
ALLOWED_HOSTS: ${NGINX_HOSTNAME}
|
ALLOWED_HOSTS: ${NGINX_HOSTNAME}
|
||||||
PYTHONDONTWRITEBYTECODE: 1
|
|
||||||
PYTHONUNBUFFERED: 1
|
|
||||||
DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE}
|
DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE}
|
||||||
VIRTUAL_HOST: localhost
|
VIRTUAL_HOST: localhost
|
||||||
#VIRTUAL_PORT: 8000
|
#VIRTUAL_PORT: 8000
|
||||||
@@ -15,6 +15,9 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- static_volume:/app/static
|
- static_volume:/app/static
|
||||||
- media_volume:/app/media
|
- media_volume:/app/media
|
||||||
|
networks:
|
||||||
|
- frontend
|
||||||
|
- backend
|
||||||
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
@@ -26,6 +29,12 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql
|
- postgres_data:/var/lib/postgresql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DBNAME}"]
|
||||||
|
interval: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- backend
|
||||||
|
|
||||||
adminer:
|
adminer:
|
||||||
image: adminer
|
image: adminer
|
||||||
@@ -33,7 +42,9 @@ services:
|
|||||||
- db
|
- db
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 127.0.0.1:8080:8080
|
||||||
|
networks:
|
||||||
|
- backend
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
image: nginx:stable
|
image: nginx:stable
|
||||||
@@ -51,15 +62,12 @@ services:
|
|||||||
- NGINX_SSL_PORT=443
|
- NGINX_SSL_PORT=443
|
||||||
depends_on:
|
depends_on:
|
||||||
- web
|
- web
|
||||||
|
networks:
|
||||||
|
- frontend
|
||||||
|
|
||||||
test:
|
networks:
|
||||||
build: .
|
frontend:
|
||||||
command: python manage.py test
|
backend:
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
profiles:
|
|
||||||
- test
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
|||||||
0
docs/architecture/decisions.md
Normal file
0
docs/architecture/decisions.md
Normal file
72
docs/templates/template.md
vendored
Normal file
72
docs/templates/template.md
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# Feature Name
|
||||||
|
|
||||||
|
> One sentence description of what this feature does and who it is for.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
<!-- Delete all that do not apply -->
|
||||||
|
`Planned` `In Progress` `In Review` `Complete` `Deferred`
|
||||||
|
|
||||||
|
## Background
|
||||||
|
<!-- Why are we building this? What problem does it solve? Link to any relevant roadmap phase. -->
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
<!-- What is included in this feature. Be explicit about what is out of scope too. -->
|
||||||
|
|
||||||
|
**In scope:**
|
||||||
|
-
|
||||||
|
|
||||||
|
**Out of scope:**
|
||||||
|
-
|
||||||
|
|
||||||
|
## User Stories
|
||||||
|
<!-- Who interacts with this feature and what do they want to achieve? -->
|
||||||
|
- As a **[member / board member / anonymous visitor]**, I want to **[action]** so that **[outcome]**.
|
||||||
|
|
||||||
|
## Data Model
|
||||||
|
<!-- What models are created or modified? List fields and their types. -->
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ExampleModel(models.Model):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**Related models:**
|
||||||
|
- `User` —
|
||||||
|
|
||||||
|
## GDPR Considerations
|
||||||
|
<!-- See docs/gdpr/ for shared policies. Only document what is specific to this feature. -->
|
||||||
|
|
||||||
|
| Question | Answer |
|
||||||
|
|---|---|
|
||||||
|
| Personal data collected | |
|
||||||
|
| Legal basis | Legitimate interest / Consent / Legal obligation |
|
||||||
|
| Retention period | See `docs/gdpr/retention-policy.md` / [custom policy] |
|
||||||
|
| Erasure behaviour | Cascade delete / Anonymise / Transfer ownership |
|
||||||
|
| Visible to non-members | Yes / No |
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
<!-- Unresolved decisions that are blocking or will affect implementation. -->
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Decisions Log
|
||||||
|
<!-- Record decisions made during development so future contributors understand why things are the way they are. -->
|
||||||
|
|
||||||
|
| Date | Decision | Reasoning |
|
||||||
|
|---|---|---|
|
||||||
|
| YYYY-MM-DD | | |
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
<!-- Break the feature down into concrete implementation steps. -->
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Related
|
||||||
|
<!-- Links to related feature files, external docs, or GitHub issues. -->
|
||||||
|
-
|
||||||
@@ -3,3 +3,7 @@ gunicorn==25.1.0
|
|||||||
psycopg [binary] ==3.3.3
|
psycopg [binary] ==3.3.3
|
||||||
django-browser-reload
|
django-browser-reload
|
||||||
django-watchfiles
|
django-watchfiles
|
||||||
|
docutils==0.22.4
|
||||||
|
ruff==0.15.9
|
||||||
|
Mypy==1.20
|
||||||
|
django-stubs==5.0.2
|
||||||
|
|||||||
0
src/gallery/__init__.py
Normal file
0
src/gallery/__init__.py
Normal file
3
src/gallery/admin.py
Normal file
3
src/gallery/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
5
src/gallery/apps.py
Normal file
5
src/gallery/apps.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class GalleryConfig(AppConfig):
|
||||||
|
name = 'gallery'
|
||||||
0
src/gallery/migrations/__init__.py
Normal file
0
src/gallery/migrations/__init__.py
Normal file
3
src/gallery/models.py
Normal file
3
src/gallery/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
3
src/gallery/tests.py
Normal file
3
src/gallery/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
src/gallery/views.py
Normal file
3
src/gallery/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
@@ -40,6 +40,7 @@ INSTALLED_APPS = [
|
|||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
|
"django.contrib.admindocs",
|
||||||
"django_browser_reload",
|
"django_browser_reload",
|
||||||
"django_watchfiles",
|
"django_watchfiles",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ from django.contrib import admin
|
|||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("__reload__/", include("django_browser_reload.urls")),
|
|
||||||
path("polls/", include("polls.urls")),
|
path("polls/", include("polls.urls")),
|
||||||
|
path("admin/doc/", include("django.contrib.admindocs.urls")),
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
|
path("__reload__/", include("django_browser_reload.urls")),
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user