From c189f5729d926b9083ba6cca1f4ec53e16d97383 Mon Sep 17 00:00:00 2001 From: Katrin Torsunova Date: Wed, 8 Jul 2026 23:24:09 +0200 Subject: [PATCH 1/2] keep cache clean with versions --- src/app.py | 22 +++++++++++++++++++++- src/templates/base.html | 27 ++++++++++++++++++--------- src/templates/milestones/edit.html | 3 ++- src/templates/milestones/new.html | 3 ++- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/app.py b/src/app.py index 682bf87..5762827 100644 --- a/src/app.py +++ b/src/app.py @@ -1,7 +1,7 @@ from contextlib import asynccontextmanager from pathlib import Path -from fastapi import FastAPI +from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from src.database import Base, engine @@ -28,6 +28,26 @@ async def lifespan(app: FastAPI): redoc_url=None, openapi_url=None, ) + + +@app.middleware("http") +async def cache_control(request: Request, call_next): + response = await call_next(request) + + if request.url.path.startswith("/static/"): + response.headers.setdefault( + "Cache-Control", + "public, max-age=31536000, immutable", + ) + return response + + content_type = response.headers.get("content-type", "") + if content_type.startswith("text/html"): + response.headers.setdefault("Cache-Control", "no-store") + + return response + + app.add_middleware(AuthMiddleware) app.include_router(auth_router) app.mount("/static", StaticFiles(directory=SRC / "static"), name="static") diff --git a/src/templates/base.html b/src/templates/base.html index 361abca..d4d3240 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -27,15 +27,24 @@ {% block styles %}{% endblock %} - - - - - - - - - + + + + + + + + +
diff --git a/src/templates/milestones/edit.html b/src/templates/milestones/edit.html index a3548ec..6a21ec9 100644 --- a/src/templates/milestones/edit.html +++ b/src/templates/milestones/edit.html @@ -39,5 +39,6 @@

Edit milestone

- + {% endblock %} diff --git a/src/templates/milestones/new.html b/src/templates/milestones/new.html index 665aca4..143e140 100644 --- a/src/templates/milestones/new.html +++ b/src/templates/milestones/new.html @@ -39,5 +39,6 @@

New milestone

- + {% endblock %} From c37166427f322112ae6e107ed838df934b06242a Mon Sep 17 00:00:00 2001 From: Katrin Torsunova Date: Wed, 8 Jul 2026 23:24:55 +0200 Subject: [PATCH 2/2] upd docs --- CONTRIBUTING.md | 1 + docs/architecture.md | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce16d10..7d66bd0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,6 +39,7 @@ All of these run in CI on every PR — a failing check won't get merged. - New features go in `src/features/`, following the existing structure (`api.py`, `services.py`, `dto.py`). - Templates live in `src/templates/`, JavaScript in `src/static/js/`. +- Keep template-linked CSS/JS versioned with `asset_version(...)` so browser caches invalidate on file changes. - The terminal bar is a navigation layer, not a shell — keep commands simple and purposeful. - Form validation belongs in DTOs (`dto.py`), not in route handlers. - Tests are expected for new Python logic; JS tests for anything in `src/static/js/`. diff --git a/docs/architecture.md b/docs/architecture.md index 09e5fe7..ae1fd47 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -167,6 +167,12 @@ On validation error, the template is returned with an `error` field — no redir The bottom bar is a navigation layer, not a shell. Commands: `help`, `new`, `tags`, `tag {name}`, `random`, `search {query}`, `tree`, `logout`. The command list is served at `/terminal/commands` and used for autocomplete. +## Cache policy + +- HTML responses should not be cached long-term. +- Versioned static assets should be cached long-term (`Cache-Control: public, max-age=31536000, immutable`). +- All CSS and JS references in templates should include `asset_version(...)` so the URL changes when file contents change. + ## Timeline `/tree` renders a chronological terminal journal using data grouped by year, month, and day. The backend helper `group_by_year_and_month` returns nested `OrderedDict` values in the shape `Year -> Month -> Day -> [Milestone]` so the template can render plain text-style output with stable alignment.