Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/`.
Expand Down
6 changes: 6 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 21 additions & 1 deletion src/app.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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")
Expand Down
27 changes: 18 additions & 9 deletions src/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,24 @@
<link rel="stylesheet"
href="/static/css/components/terminal-tree.css?v={{ asset_version("css/components/terminal-tree.css") }}">
{% block styles %}{% endblock %}
<script src="/static/js/autocomplete/core.js" defer></script>
<script src="/static/js/terminal/history.js" defer></script>
<script src="/static/js/autocomplete/terminal.js" defer></script>
<script src="/static/js/autocomplete/tags.js" defer></script>
<script src="/static/js/terminal/input.js" defer></script>
<script src="/static/js/terminal/input-mobile.js" defer></script>
<script src="/static/js/terminal/table.js" defer></script>
<script src="/static/js/keyboard/global.js" defer></script>
<script src="/static/js/terminal/navigation.js" defer></script>
<script src="/static/js/autocomplete/core.js?v={{ asset_version("js/autocomplete/core.js") }}"
defer></script>
<script src="/static/js/terminal/history.js?v={{ asset_version("js/terminal/history.js") }}"
defer></script>
<script src="/static/js/autocomplete/terminal.js?v={{ asset_version("js/autocomplete/terminal.js") }}"
defer></script>
<script src="/static/js/autocomplete/tags.js?v={{ asset_version("js/autocomplete/tags.js") }}"
defer></script>
<script src="/static/js/terminal/input.js?v={{ asset_version("js/terminal/input.js") }}"
defer></script>
<script src="/static/js/terminal/input-mobile.js?v={{ asset_version("js/terminal/input-mobile.js") }}"
defer></script>
<script src="/static/js/terminal/table.js?v={{ asset_version("js/terminal/table.js") }}"
defer></script>
<script src="/static/js/keyboard/global.js?v={{ asset_version("js/keyboard/global.js") }}"
defer></script>
<script src="/static/js/terminal/navigation.js?v={{ asset_version("js/terminal/navigation.js") }}"
defer></script>
</head>
<body>
<main>
Expand Down
3 changes: 2 additions & 1 deletion src/templates/milestones/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ <h1>Edit milestone</h1>
</label>
<button type="submit">Save</button>
</form>
<script src="/static/js/milestones/date.js" defer></script>
<script src="/static/js/milestones/date.js?v={{ asset_version("js/milestones/date.js") }}"
defer></script>
{% endblock %}
3 changes: 2 additions & 1 deletion src/templates/milestones/new.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ <h1>New milestone</h1>
</datalist>
<button type="submit">Save</button>
</form>
<script src="/static/js/milestones/date.js" defer></script>
<script src="/static/js/milestones/date.js?v={{ asset_version("js/milestones/date.js") }}"
defer></script>
{% endblock %}
Loading