add project structure

This commit is contained in:
2026-04-19 12:13:07 +02:00
commit dae7a60eab
16 changed files with 437 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
+13
View File
@@ -0,0 +1,13 @@
import os
from dataclasses import dataclass
@dataclass(slots=True)
class Settings:
database_url: str = os.getenv("DATABASE_URL", "sqlite:///./data/app.db")
host: str = os.getenv("HOST", "0.0.0.0")
port: int = int(os.getenv("PORT", "10000"))
def get_settings() -> Settings:
return Settings()
+44
View File
@@ -0,0 +1,44 @@
from typing import Generator
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
from app.config import get_settings
engine = None
SessionLocal = sessionmaker(autocommit=False, autoflush=False)
class Base(DeclarativeBase):
pass
def _build_engine(database_url: str):
connect_args = {"check_same_thread": False} if database_url.startswith("sqlite") else {}
return create_engine(database_url, connect_args=connect_args)
def configure_database(database_url: str | None = None) -> None:
global engine
settings = get_settings()
resolved_database_url = database_url or settings.database_url
engine = _build_engine(resolved_database_url)
SessionLocal.configure(bind=engine)
def get_db() -> Generator[Session, None, None]:
db = SessionLocal()
try:
yield db
finally:
db.close()
def init_db(database_url: str | None = None) -> None:
from app import models
if engine is None or database_url is not None:
configure_database(database_url)
Base.metadata.create_all(bind=engine)
+37
View File
@@ -0,0 +1,37 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from app.db import init_db
templates = Jinja2Templates(directory="app/templates")
def create_app() -> FastAPI:
@asynccontextmanager
async def lifespan(app: FastAPI):
init_db()
yield
app = FastAPI(title="Moving Helper", lifespan=lifespan)
app.mount("/static", StaticFiles(directory="app/static"), name="static")
@app.get("/", include_in_schema=False)
def root() -> RedirectResponse:
return RedirectResponse(url="/boxes", status_code=302)
@app.get("/boxes")
def boxes_page(request: Request):
return templates.TemplateResponse(
request=request,
name="boxes.html",
context={"page_title": "Boxes"},
)
return app
app = create_app()
+15
View File
@@ -0,0 +1,15 @@
from datetime import datetime
from sqlalchemy import DateTime, String
from sqlalchemy.orm import Mapped, mapped_column
from app.db import Base
class Box(Base):
__tablename__ = "boxes"
id: Mapped[int] = mapped_column(primary_key=True, index=True)
name: Mapped[str] = mapped_column(String(100), nullable=False, default="Sample Box")
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
+20
View File
@@ -0,0 +1,20 @@
body {
margin: 0;
font-family: Arial, sans-serif;
background: #f4f4f4;
color: #222;
}
.container {
max-width: 720px;
margin: 48px auto;
padding: 24px;
background: #fff;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
h1 {
margin-top: 0;
}
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ page_title or "Moving Helper" }}</title>
<link rel="stylesheet" href="{{ url_for('static', path='/style.css') }}">
</head>
<body>
<main class="container">
{% block content %}{% endblock %}
</main>
</body>
</html>
+7
View File
@@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block content %}
<h1>Boxes page</h1>
<p>This is the minimal starter page for the boxes module.</p>
{% endblock %}