Refactor backend structure: update Dockerfile, improve database connection, and enhance dev_seed functionality
This commit is contained in:
parent
cb213afdf4
commit
e9bc26e1ed
13 changed files with 150 additions and 128 deletions
|
|
@ -1,11 +1,13 @@
|
||||||
|
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY requirements.txt .
|
COPY requirements.txt ./
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD [ "uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload" ]
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import Iterable, List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
from uuid import UUID as UUID_t
|
from uuid import UUID as UUID_t
|
||||||
from datetime import date
|
from datetime import date
|
||||||
import re, ast, operator
|
import re, ast
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
import models
|
from backend import models
|
||||||
|
|
||||||
ALLOWED_NAMES = {"days", "nights"}
|
ALLOWED_NAMES = {"days", "nights"}
|
||||||
ALLOWED_NODES = (
|
ALLOWED_NODES = (
|
||||||
|
|
@ -74,7 +75,7 @@ def generate_trip_items(
|
||||||
trip: models.Trip,
|
trip: models.Trip,
|
||||||
selected_tag_ids: List[UUID_t],
|
selected_tag_ids: List[UUID_t],
|
||||||
marked_tag_ids: List[UUID_t],
|
marked_tag_ids: List[UUID_t],
|
||||||
) -> Tuple[List[models.TripItem], List[UUID_t]]:
|
) -> Tuple[List[UUID_t], List[UUID_t]]:
|
||||||
"""Regeneriert TripItems für einen Trip. Löscht alte, legt neue an.
|
"""Regeneriert TripItems für einen Trip. Löscht alte, legt neue an.
|
||||||
Gibt (created_ids, deleted_checked_ids) zurück."""
|
Gibt (created_ids, deleted_checked_ids) zurück."""
|
||||||
# Sammle bestehende checked Items, falls sie verschwinden
|
# Sammle bestehende checked Items, falls sie verschwinden
|
||||||
|
|
@ -94,12 +95,8 @@ def generate_trip_items(
|
||||||
|
|
||||||
for it in items:
|
for it in items:
|
||||||
item_tag_ids = {link.tag_id for link in it.tags}
|
item_tag_ids = {link.tag_id for link in it.tags}
|
||||||
# bestimmen, ob dupliziert werden soll
|
|
||||||
intersection = item_tag_ids & marked_set
|
intersection = item_tag_ids & marked_set
|
||||||
if marked_set and intersection:
|
per_tags = sorted(list(intersection)) if (marked_set and intersection) else [None]
|
||||||
per_tags = sorted(list(intersection))
|
|
||||||
else:
|
|
||||||
per_tags = [None] # gemeinsames Item (oder keine marked match)
|
|
||||||
|
|
||||||
for tag_id in per_tags:
|
for tag_id in per_tags:
|
||||||
calc = render_name(it.name, trip.start_date, trip.end_date)
|
calc = render_name(it.name, trip.start_date, trip.end_date)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||||
|
|
||||||
|
|
@ -7,9 +8,6 @@ engine = create_engine(DATABASE_URL, future=True)
|
||||||
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
|
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False, future=True)
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
# FastAPI dependency
|
|
||||||
from contextlib import contextmanager
|
|
||||||
|
|
||||||
def get_db():
|
def get_db():
|
||||||
db = SessionLocal()
|
db = SessionLocal()
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
from uuid import UUID
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from database import Base, engine
|
from backend.database import Base, engine
|
||||||
from routes import items, tags, trips, trip_items, dev_seed
|
from backend.routes import items, tags, trips, trip_items, dev_seed
|
||||||
|
|
||||||
|
|
||||||
# Create tables (for MVP without Alembic)
|
# Create tables (for MVP without Alembic)
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
from sqlalchemy import (
|
from sqlalchemy import Column, String, Boolean, Date, ForeignKey, UniqueConstraint
|
||||||
Column, String, Boolean, Date, ForeignKey, UniqueConstraint
|
|
||||||
)
|
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from database import Base
|
from backend.database import Base
|
||||||
|
|
||||||
|
|
||||||
class User(Base):
|
class User(Base):
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
|
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
name = Column(String, nullable=False)
|
name = Column(String, nullable=False)
|
||||||
|
|
||||||
|
|
@ -17,10 +14,8 @@ class User(Base):
|
||||||
tags = relationship("Tag", back_populates="user", cascade="all, delete")
|
tags = relationship("Tag", back_populates="user", cascade="all, delete")
|
||||||
trips = relationship("Trip", back_populates="user", cascade="all, delete")
|
trips = relationship("Trip", back_populates="user", cascade="all, delete")
|
||||||
|
|
||||||
|
|
||||||
class Item(Base):
|
class Item(Base):
|
||||||
__tablename__ = "items"
|
__tablename__ = "items"
|
||||||
|
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||||
name = Column(String, nullable=False) # z.B. "Zahnbürste" oder "{days} x Vitamin D3"
|
name = Column(String, nullable=False) # z.B. "Zahnbürste" oder "{days} x Vitamin D3"
|
||||||
|
|
@ -29,10 +24,9 @@ class Item(Base):
|
||||||
tags = relationship("ItemTag", back_populates="item", cascade="all, delete")
|
tags = relationship("ItemTag", back_populates="item", cascade="all, delete")
|
||||||
trip_items = relationship("TripItem", back_populates="item", cascade="all, delete")
|
trip_items = relationship("TripItem", back_populates="item", cascade="all, delete")
|
||||||
|
|
||||||
|
|
||||||
class Tag(Base):
|
class Tag(Base):
|
||||||
__tablename__ = "tags"
|
__tablename__ = "tags"
|
||||||
__table_args__ = (UniqueConstraint("user_id", "name"),)
|
__table_args__ = (UniqueConstraint("user_id", "name", name="uq_tag_user_name"),)
|
||||||
|
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||||
|
|
@ -44,20 +38,16 @@ class Tag(Base):
|
||||||
trip_marked_tags = relationship("TripTagMarked", back_populates="tag", cascade="all, delete")
|
trip_marked_tags = relationship("TripTagMarked", back_populates="tag", cascade="all, delete")
|
||||||
trip_items = relationship("TripItem", back_populates="tag")
|
trip_items = relationship("TripItem", back_populates="tag")
|
||||||
|
|
||||||
|
|
||||||
class ItemTag(Base):
|
class ItemTag(Base):
|
||||||
__tablename__ = "item_tags"
|
__tablename__ = "item_tags"
|
||||||
|
|
||||||
item_id = Column(UUID(as_uuid=True), ForeignKey("items.id", ondelete="CASCADE"), primary_key=True)
|
item_id = Column(UUID(as_uuid=True), ForeignKey("items.id", ondelete="CASCADE"), primary_key=True)
|
||||||
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id", ondelete="CASCADE"), primary_key=True)
|
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id", ondelete="CASCADE"), primary_key=True)
|
||||||
|
|
||||||
item = relationship("Item", back_populates="tags")
|
item = relationship("Item", back_populates="tags")
|
||||||
tag = relationship("Tag", back_populates="items")
|
tag = relationship("Tag", back_populates="items")
|
||||||
|
|
||||||
|
|
||||||
class Trip(Base):
|
class Trip(Base):
|
||||||
__tablename__ = "trips"
|
__tablename__ = "trips"
|
||||||
|
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False)
|
||||||
name = Column(String)
|
name = Column(String)
|
||||||
|
|
@ -69,36 +59,30 @@ class Trip(Base):
|
||||||
marked_tags = relationship("TripTagMarked", back_populates="trip", cascade="all, delete")
|
marked_tags = relationship("TripTagMarked", back_populates="trip", cascade="all, delete")
|
||||||
trip_items = relationship("TripItem", back_populates="trip", cascade="all, delete")
|
trip_items = relationship("TripItem", back_populates="trip", cascade="all, delete")
|
||||||
|
|
||||||
|
|
||||||
class TripTagSelected(Base):
|
class TripTagSelected(Base):
|
||||||
__tablename__ = "trip_tag_selected"
|
__tablename__ = "trip_tag_selected"
|
||||||
|
|
||||||
trip_id = Column(UUID(as_uuid=True), ForeignKey("trips.id", ondelete="CASCADE"), primary_key=True)
|
trip_id = Column(UUID(as_uuid=True), ForeignKey("trips.id", ondelete="CASCADE"), primary_key=True)
|
||||||
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id"), primary_key=True)
|
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id"), primary_key=True)
|
||||||
|
|
||||||
trip = relationship("Trip", back_populates="selected_tags")
|
trip = relationship("Trip", back_populates="selected_tags")
|
||||||
tag = relationship("Tag", back_populates="trip_selected_tags")
|
tag = relationship("Tag", back_populates="trip_selected_tags")
|
||||||
|
|
||||||
|
|
||||||
class TripTagMarked(Base):
|
class TripTagMarked(Base):
|
||||||
__tablename__ = "trip_tag_marked"
|
__tablename__ = "trip_tag_marked"
|
||||||
|
|
||||||
trip_id = Column(UUID(as_uuid=True), ForeignKey("trips.id", ondelete="CASCADE"), primary_key=True)
|
trip_id = Column(UUID(as_uuid=True), ForeignKey("trips.id", ondelete="CASCADE"), primary_key=True)
|
||||||
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id"), primary_key=True)
|
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id"), primary_key=True)
|
||||||
|
|
||||||
trip = relationship("Trip", back_populates="marked_tags")
|
trip = relationship("Trip", back_populates="marked_tags")
|
||||||
tag = relationship("Tag", back_populates="trip_marked_tags")
|
tag = relationship("Tag", back_populates="trip_marked_tags")
|
||||||
|
|
||||||
|
|
||||||
class TripItem(Base):
|
class TripItem(Base):
|
||||||
__tablename__ = "trip_items"
|
__tablename__ = "trip_items"
|
||||||
|
|
||||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
trip_id = Column(UUID(as_uuid=True), ForeignKey("trips.id", ondelete="CASCADE"), nullable=False)
|
trip_id = Column(UUID(as_uuid=True), ForeignKey("trips.id", ondelete="CASCADE"), nullable=False)
|
||||||
item_id = Column(UUID(as_uuid=True), ForeignKey("items.id"), nullable=False)
|
item_id = Column(UUID(as_uuid=True), ForeignKey("items.id"), nullable=False)
|
||||||
name_calculated = Column(String, nullable=False)
|
name_calculated = Column(String, nullable=False)
|
||||||
checked = Column(Boolean, nullable=False, default=False)
|
checked = Column(Boolean, nullable=False, default=False)
|
||||||
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id"), nullable=True)
|
tag_id = Column(UUID(as_uuid=True), ForeignKey("tags.id"), nullable=True) # null = gemeinsames Item
|
||||||
|
|
||||||
trip = relationship("Trip", back_populates="trip_items")
|
trip = relationship("Trip", back_populates="trip_items")
|
||||||
item = relationship("Item", back_populates="trip_items")
|
item = relationship("Item", back_populates="trip_items")
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
fastapi
|
|
||||||
uvicorn[standard]
|
|
||||||
sqlalchemy
|
|
||||||
asyncpg
|
|
||||||
psycopg2-binary
|
|
||||||
pydantic
|
|
||||||
python-dotenv
|
|
||||||
|
|
||||||
|
fastapi==0.115.0
|
||||||
|
uvicorn==0.30.6
|
||||||
|
SQLAlchemy==2.0.34
|
||||||
|
psycopg2-binary==2.9.9
|
||||||
|
pydantic==1.10.17
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,103 @@
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
import uuid
|
from uuid import uuid4
|
||||||
from database import get_db
|
from datetime import date, timedelta
|
||||||
import models
|
from backend.database import get_db
|
||||||
|
from backend import models
|
||||||
FIXED_USER_ID = uuid.UUID("00000000-0000-0000-0000-000000000001") # Fixed UUID for demo user
|
from backend.crud import generate_trip_items
|
||||||
|
|
||||||
router = APIRouter(tags=["dev"])
|
router = APIRouter(tags=["dev"])
|
||||||
|
|
||||||
@router.get("/dev/seed")
|
@router.get("/dev/seed")
|
||||||
def seed_data(db: Session = Depends(get_db)):
|
|
||||||
user_id = FIXED_USER_ID
|
|
||||||
|
|
||||||
# Create demo user if not exists
|
def dev_seed(db: Session = Depends(get_db)):
|
||||||
user = db.query(models.User).filter(models.User.id == user_id).first()
|
|
||||||
|
# Create demo user
|
||||||
|
user = db.query(models.User).first()
|
||||||
if not user:
|
if not user:
|
||||||
user = models.User(id=user_id, name="Demo User")
|
user = models.User(id=uuid4(), name="Demo")
|
||||||
db.add(user)
|
db.add(user)
|
||||||
db.flush()
|
db.flush()
|
||||||
|
|
||||||
# Tags
|
# Tags
|
||||||
tags = ["jari", "kristin", "felix", "auto", "sommer"]
|
tag_names = ["jari", "kristin", "felix", "auto", "sommer"]
|
||||||
tag_objs = []
|
name_to_tag = {}
|
||||||
for t in tags:
|
for name in tag_names:
|
||||||
tag_obj = models.Tag(id=uuid.uuid4(), user_id=user_id, name=t)
|
existing = db.query(models.Tag).filter(models.Tag.user_id==user.id, models.Tag.name==name).first()
|
||||||
db.add(tag_obj)
|
if existing:
|
||||||
tag_objs.append(tag_obj)
|
name_to_tag[name] = existing
|
||||||
|
else:
|
||||||
|
t = models.Tag(id=uuid4(), user_id=user.id, name=name)
|
||||||
|
db.add(t)
|
||||||
|
db.flush()
|
||||||
|
name_to_tag[name] = t
|
||||||
|
|
||||||
|
# Items (based on your original example)
|
||||||
|
|
||||||
|
items = [
|
||||||
|
("Kinderwagen", ["jari"]),
|
||||||
|
("Babyschale mit Sonnenschutz", ["jari", "auto"]),
|
||||||
|
("Alle Schnuller", ["jari"]),
|
||||||
|
("Sonnencreme", ["sommer"]),
|
||||||
|
("Ladekabel Handy", []),
|
||||||
|
("Ladekabel Mac", ["kristin"]),
|
||||||
|
("Sonnenbrillen", ["sommer"]),
|
||||||
|
("Schlafsack für {nights} Nächte", ["jari"]),
|
||||||
|
("{days} x Vitamin D3", ["jari"]),
|
||||||
|
("{days * 10} Windeln", ["jari"]),
|
||||||
|
("{days} Unterhosen", ["felix", "kristin"]),
|
||||||
|
("Badesachen", ["felix", "kristin"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
for name, tags in items:
|
||||||
|
existing = db.query(models.Item).filter(models.Item.user_id==user.id, models.Item.name==name).first()
|
||||||
|
if existing:
|
||||||
|
item = existing
|
||||||
|
else:
|
||||||
|
item = models.Item(id=uuid4(), user_id=user.id, name=name)
|
||||||
|
db.add(item)
|
||||||
|
db.flush()
|
||||||
|
|
||||||
|
# link tags
|
||||||
|
for tag_name in tags:
|
||||||
|
tag = name_to_tag[tag_name]
|
||||||
|
link = db.query(models.ItemTag).filter_by(item_id=item.id, tag_id=tag.id).first()
|
||||||
|
if not link:
|
||||||
|
db.add(models.ItemTag(item_id=item.id, tag_id=tag.id))
|
||||||
|
|
||||||
db.flush()
|
db.flush()
|
||||||
|
|
||||||
# Items
|
# Demo trip
|
||||||
items_data = [
|
|
||||||
("Badesachen", ["sommer", "auto"]),
|
|
||||||
("Sonnencreme", ["sommer"]),
|
|
||||||
("Ladegerät", []),
|
|
||||||
("Zelt", ["auto"]),
|
|
||||||
("Schlafsack", []),
|
|
||||||
("Strandspielzeug", ["sommer", "jari"]),
|
|
||||||
]
|
|
||||||
for name, tag_names in items_data:
|
|
||||||
item = models.Item(id=uuid.uuid4(), user_id=user_id, name=name)
|
|
||||||
db.add(item)
|
|
||||||
db.flush()
|
|
||||||
for tag_name in tag_names:
|
|
||||||
tag_id = next(t.id for t in tag_objs if t.name == tag_name)
|
|
||||||
db.add(models.ItemTag(item_id=item.id, tag_id=tag_id))
|
|
||||||
|
|
||||||
selected_tags = [t for t in tag_objs if t.name in ["jari", "kristin", "auto", "sommer"]]
|
|
||||||
marked_tags = [t for t in tag_objs if t.name in ["kristin", "felix"]]
|
|
||||||
trip = models.Trip(
|
trip = models.Trip(
|
||||||
id=uuid.uuid4(),
|
id=uuid4(),
|
||||||
user_id=user_id,
|
user_id=user.id,
|
||||||
name="Ostsee August 2025",
|
name="Ostsee August 2025",
|
||||||
start_date="2025-08-01",
|
start_date=date(2025, 8, 18),
|
||||||
end_date="2025-08-14",
|
end_date=date(2025, 8, 20),
|
||||||
selected_tags=selected_tags,
|
|
||||||
marked_tags=marked_tags,
|
|
||||||
)
|
)
|
||||||
db.add(trip)
|
db.add(trip)
|
||||||
|
db.flush()
|
||||||
|
|
||||||
|
selected = [name_to_tag[n].id for n in ["jari", "felix", "kristin", "auto"]]
|
||||||
|
marked = [name_to_tag[n].id for n in ["kristin", "felix"]]
|
||||||
|
|
||||||
|
for tid in selected:
|
||||||
|
db.add(models.TripTagSelected(trip_id=trip.id, tag_id=tid))
|
||||||
|
|
||||||
|
for tid in marked:
|
||||||
|
db.add(models.TripTagMarked(trip_id=trip.id, tag_id=tid))
|
||||||
|
|
||||||
|
db.flush()
|
||||||
|
|
||||||
|
created_ids, _ = generate_trip_items(db, trip=trip, selected_tag_ids=selected, marked_tag_ids=marked)
|
||||||
|
|
||||||
db.commit()
|
db.commit()
|
||||||
return {"message": "Seed data created", "user_id": str(user_id)}
|
|
||||||
|
return {
|
||||||
|
"user_id": str(user.id),
|
||||||
|
"trip_id": str(trip.id),
|
||||||
|
"selected_tag_ids": [str(x) for x in selected],
|
||||||
|
"marked_tag_ids": [str(x) for x in marked],
|
||||||
|
"created_trip_item_ids": [str(x) for x in created_ids],
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from database import get_db
|
from backend.database import get_db
|
||||||
import models
|
from backend import models
|
||||||
from schemas import ItemCreate, ItemOut
|
from backend.schemas import ItemCreate, ItemOut
|
||||||
|
|
||||||
router = APIRouter(prefix="/items", tags=["items"])
|
router = APIRouter(prefix="/items", tags=["items"])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from database import get_db
|
from backend.database import get_db
|
||||||
import models
|
from backend import models
|
||||||
from schemas import TagCreate, TagOut
|
from backend.schemas import TagCreate, TagOut
|
||||||
|
|
||||||
router = APIRouter(prefix="/tags", tags=["tags"])
|
router = APIRouter(prefix="/tags", tags=["tags"])
|
||||||
|
|
||||||
FIXED_USER_ID = None # will be created on seed; or set in your auth layer
|
|
||||||
|
|
||||||
@router.get("/", response_model=list[TagOut])
|
@router.get("/", response_model=list[TagOut])
|
||||||
def list_tags(db: Session = Depends(get_db)):
|
def list_tags(db: Session = Depends(get_db)):
|
||||||
tags = db.query(models.Tag).all()
|
tags = db.query(models.Tag).all()
|
||||||
|
|
@ -16,7 +15,6 @@ def list_tags(db: Session = Depends(get_db)):
|
||||||
|
|
||||||
@router.post("/", response_model=TagOut)
|
@router.post("/", response_model=TagOut)
|
||||||
def create_tag(payload: TagCreate, db: Session = Depends(get_db)):
|
def create_tag(payload: TagCreate, db: Session = Depends(get_db)):
|
||||||
# For MVP: attach to first user (or create one)
|
|
||||||
user = db.query(models.User).first()
|
user = db.query(models.User).first()
|
||||||
if not user:
|
if not user:
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from database import get_db
|
from backend.database import get_db
|
||||||
import models
|
from backend import models
|
||||||
from schemas import TripItemOut
|
from backend.schemas import TripItemOut
|
||||||
|
|
||||||
router = APIRouter(prefix="/trip-items", tags=["trip-items"])
|
router = APIRouter(prefix="/trip-items", tags=["trip-items"])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from database import get_db
|
from backend.database import get_db
|
||||||
import models
|
from backend import models
|
||||||
from schemas import TripCreate, TripOut, TripUpdate, TripRegenerationResult
|
from backend.schemas import TripCreate, TripOut, TripUpdate, TripRegenerationResult
|
||||||
from crud import generate_trip_items
|
from backend.crud import generate_trip_items
|
||||||
|
|
||||||
router = APIRouter(prefix="/trips", tags=["trips"])
|
router = APIRouter(prefix="/trips", tags=["trips"])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
version: "3.9"
|
|
||||||
|
|
||||||
|
version: "3.9"
|
||||||
services:
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_DB: postgres
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/postgresql/data
|
||||||
backend:
|
backend:
|
||||||
build: ./backend
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend:/app
|
- ./:/app
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/packlist
|
- PYTHONUNBUFFERED=1
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: postgres:15
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: packlist
|
|
||||||
volumes:
|
|
||||||
- db_data:/var/lib/postgresql/data
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
db_data:
|
db_data:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue