add journaling feature: categories, tags, attachments, calendar, and multi-select emotions

Adds an 8th development stage that lets users keep a free-form journal alongside
habit tracking, reusing the existing Google OAuth/DB/PWA infrastructure instead
of a separate project. Users organize entries into custom categories, filter by
a month calendar with day-detail drill-down, attach photos/videos (served via an
authenticated route, never /static), tag entries, and pick multiple emotions per
entry from a curated 9-option set. Includes a global journal prompt bank for
lightweight guided journaling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 18:40:07 +09:00
co-authored by Claude Sonnet 5
parent ef2a3ea082
commit 54c971875c
24 changed files with 2485 additions and 7 deletions
+5 -1
View File
@@ -1,5 +1,6 @@
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
@@ -9,7 +10,7 @@ from starlette.middleware.sessions import SessionMiddleware
from app.config import settings
from app.database import SessionLocal
from app.routers import auth, habits, logs, pages, push
from app.routers import auth, habits, journal, journal_pages, logs, pages, push
from app.routers.pages import templates
from app.security import get_current_user_optional
from app.services import scheduler_service
@@ -19,6 +20,7 @@ logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
Path(settings.journal_media_root).mkdir(parents=True, exist_ok=True)
scheduler_service.start_scheduler()
yield
scheduler_service.shutdown_scheduler()
@@ -44,8 +46,10 @@ app.mount("/static", StaticFiles(directory="app/static"), name="static")
app.include_router(auth.router)
app.include_router(habits.router)
app.include_router(journal.router)
app.include_router(logs.router)
app.include_router(push.router)
app.include_router(journal_pages.router)
app.include_router(pages.router)