diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0160de286dfe601ae0590f0cf90d1c6ecc375628
--- /dev/null
+++ b/README.md
@@ -0,0 +1,66 @@
+# Chaos Parcel Serivce: Backend
+
+## Deployment
+This assumes you run the code as user *www-data*  
+Do **not** checkout this code as the same user.  
+checkout the code (main branch for production)  
+cd into the directory  
+
+```
+mkdir instance
+chown www-data:www-data instance
+```
+
+create a file .env with content
+```
+# the database location relative to the repository root
+database_url = "sqlite:///instance/paketshop.db"
+# the url for the customer frontend (the people sending parcels)
+customer_url = "https://bgp.events.ccc.de"
+# the url this app will be run under
+backend_url = "https://backend.bgp.events.ccc.de"
+# the url for the people handling the parcels
+worker_url = "https://intern.bgp.events.ccc.de"
+# a shared secret for the workers
+shared_secret = "{{ bgp_secrets.shared_secret }}"
+# a deployment wide secret key. 
+# can be created with:
+# python3 -c 'import os; print(os.urandom(16).hex())'
+signing_key = "{{ bgp_secrets.signing_key }}"
+# how long workers are logged in.
+token_lifetime = "180"
+```
+
+create a venv and install requirements:
+```
+python -m venv venv
+. venv/bin/activate
+pip install -r requirements.txt
+```
+
+We suggest to use gunicorn to server the python app, so install it
+```
+pip install gunicorn
+```
+
+create a runtime directory to allow the webserver to forward calls to
+```
+mdkir /run/bgp
+chown www-data:www-data /run/bgp
+```
+
+create a systemd service file to serve the app:
+```
+[Unit]
+Description=Gunicorn instance to serve bgp backend fastapi app
+After=network.target
+
+[Service]
+User=www-data
+Group=www-data
+WorkingDirectory=/srv/backend
+ExecStart=/srv/backend/venv/bin/gunicorn -k uvicorn.workers.UvicornWorker --bind unix:/run/bgp/socket backend.main:app
+
+[Install]
+WantedBy=multi-user.target
+```
diff --git a/backend/config.py b/backend/config.py
index d2da3f07872bba843eced0e34f67085c5b7798f4..ab4cd389ec28e9dfdc706782cbc637c35dd91917 100644
--- a/backend/config.py
+++ b/backend/config.py
@@ -8,9 +8,15 @@ class Settings(BaseSettings):
     backend_url: str = "http://localhost:8000"
     customer_url: str = "http://localhost:3000"
     worker_url: str = "http://localhost:3002"
+
+    # well known password for workers
     shared_secret: str = "worker_secret"
+    # app data signing key (global for all users. keep this secret)
     signing_key: str = "2d18526256a001bc0553c9957897d75d"
-    token_lifetime: int = 60  # auth token lifetime
+    # lifetime for auth tokens
+    token_lifetime: int = 60
+    # length of delivery tags (address-tag, keep this short but unique)
+    tag_length: int = 8
 
     class Config:
         env_file = ".env"
diff --git a/backend/main.py b/backend/main.py
index 562a1df1b003c4b892b69ea3995d22233d34c4c8..d9a8d300fe8f95a6b9ac8205675f1120b9715dea 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -1,3 +1,4 @@
+from typing import List
 from uuid import UUID
 
 from fastapi import Depends, FastAPI, HTTPException, Request, UploadFile, status
@@ -47,6 +48,13 @@ def get_db():
         db.close()
 
 
+# oauth2/token handling
+@app.get("/token")
+def check_token_validity(token: str = Depends(oauth2_scheme)):
+    check_token(token, None)
+
+
+# TODO: move this to utils.py?
 def check_token(token: str, item_uuid: str):
     try:
         auth_data = oauth2_tokener.loads(token, max_age=settings.token_lifetime * 60)
@@ -63,141 +71,223 @@ def check_token(token: str, item_uuid: str):
     )
 
 
-# Routes
-@app.post("/item/prepare", response_model=schemas.Item)
+@app.post("/token")
+def verify_supporter(form_data: OAuth2PasswordRequestForm = Depends()):
+    if form_data.password != settings.shared_secret:
+        raise HTTPException(status_code=400, detail="Incorrect username or password")
+    return {
+        "access_token": oauth2_tokener.dumps("all"),
+        "token_type": "bearer",
+    }
+
+
+# TODO: merge this with the supporter login? we want a single endpoint for all of this.
+@app.post("/login")
+def verify_customer(
+    login_data: schemas.LoginData, db: Session = Depends(get_db)
+):  # item_uuid: str, signature: str):
+    print(login_data)
+    delivery = utils.get_delivery_by_uuid(db, UUID(login_data.delivery_uuid))
+    if not delivery:
+        raise HTTPException(status_code=404, detail="Item not found")
+    if not utils.verify_signature(delivery, delivery.uuid, login_data.signature):
+        raise HTTPException(status_code=400, detail="Invalid signature")
+    return {
+        "access_token": oauth2_tokener.dumps(str(delivery.uuid)),
+        "token_type": "bearer",
+    }
+
+
+# main app
+@app.post("/delivery", response_model=schemas.Delivery)
 @limiter.limit("2/minute")
-def add_item(
-    request: Request,
-    item: schemas.ItemCreatePrepareShipping,
+def prepare_delivery(
+    request: Request, delivery: schemas.DeliveryBase, db: Session = Depends(get_db)
+):
+    return utils.prepare_delivery(db, delivery.verification)
+
+
+@app.get("/delivery/{delivery_uuid}", response_model=schemas.Delivery)
+def get_delivery_by_uuid(
+    delivery_uuid: str,
+    token: str = Depends(oauth2_scheme),
     db: Session = Depends(get_db),
 ):
-    return utils.prepare_item_shipping(db, item)
+    check_token(token, delivery_uuid)
+    delivery = utils.get_delivery_by_uuid(db, UUID(delivery_uuid))
+    if not delivery:
+        raise HTTPException(status_code=404, detail="Item not found")
+    return delivery
 
 
-@app.post("/item/register", response_model=schemas.Item)
-def add_item_with_image(
-    image: UploadFile,
+@app.get("/tag/{delivery_tag}", response_model=schemas.Delivery)
+def get_delivery_by_tag(
+    delivery_tag: str,
     token: str = Depends(oauth2_scheme),
     db: Session = Depends(get_db),
 ):
-    check_token(token, None)
-    print(image.file)
-    return utils.add_item_with_image(db, image)
+    delivery = utils.get_delivery_by_tag(db, delivery_tag)
+    check_token(token, delivery.uuid)
+    return delivery
 
 
-@app.post("/item/update/{item_uuid}", response_model=schemas.Item)
-def update_item(
-    item_uuid: str,
-    data: schemas.ItemUpdate,
+@app.put("/delivery/{delivery_uuid}", response_model=schemas.Delivery)
+def update_delivery(
+    delivery_uuid: str,
+    data: schemas.DeliveryUpdate,
     token: str = Depends(oauth2_scheme),
     db: Session = Depends(get_db),
 ):
-    check_token(token, item_uuid)
-    item = utils.get_item_by_uuid(db, UUID(item_uuid))
-    if not item:
-        raise HTTPException(status_code=404, detail="Item not found")
-    return utils.update_item(db, item, data)
+    check_token(token, delivery_uuid)
+    delivery = utils.update_delivery_data(db, UUID(delivery_uuid), data)
+    return delivery
+
+
+@app.post("/item", response_model=schemas.Item)
+def add_item(
+    item: schemas.ItemAdd,
+    token: str = Depends(oauth2_scheme),
+    db: Session = Depends(get_db),
+):
+    check_token(token, None)
+    delivery = utils.get_delivery_by_uuid(db, item.delivery_uuid)
+    storage = utils.get_storage_by_name(db, item.storage_name)
+    if not delivery:
+        raise HTTPException(status_code=404, detail="Delivery not found")
+    if not storage:
+        raise HTTPException(status_code=404, detail="Storage not found")
+    return utils.add_item_for_delivery_at_storage(
+        db, item.delivery_uuid, item.storage_name
+    )
 
 
 @app.get("/item/{item_uuid}", response_model=schemas.Item)
 def get_item(
     item_uuid: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
 ):
-    item = utils.get_item_by_uuid(db, UUID(item_uuid))
-    if not item:
-        raise HTTPException(status_code=404, detail="Item not found")
-    return item
-
-
-@app.get("/items", response_model=list[schemas.Item])
-def get_items(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
-    print(token)
-    check_token(token, None)
-    return utils.get_stored_items(db)
+    return utils.get_item_by_uuid(db, UUID(item_uuid))
 
 
-@app.get("/tag/{tag}", response_model=schemas.Item)
-def get_item_by_tag(
-    tag: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
+@app.delete("/item/{item_uuid}", response_model=schemas.Item)
+def deploy_item(
+    item_uuid: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
 ):
     check_token(token, None)
-    item = utils.get_item_by_tag(db, tag)
-    if not item:
-        raise HTTPException(status_code=404, detail="Item not found")
-    return item
+    return utils.deploy_item(db, UUID(item_uuid))
 
 
-@app.get("/storage/{storage_name}", response_model=list[schemas.Item])
+@app.get("/storage/{storage_name}", response_model=schemas.Storage)
 def get_storage(
     storage_name: str,
     token: str = Depends(oauth2_scheme),
     db: Session = Depends(get_db),
 ):
     check_token(token, None)
-    return utils.get_items_for_storage(db, storage_name)
-
-
-@app.get("/storages", response_model=list[schemas.Storage])
-def list_storages(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
-    check_token(token, None)
-    return utils.get_storages(db)
+    return utils.get_storage_by_name(db, storage_name)
 
 
-@app.post("/checkin", response_model=schemas.Item)
-def checkin_item_by_uuid(
-    checkin: schemas.ItemCheckin,
+@app.get("/storages", response_model=List[schemas.Storage])
+def get_storages(
     token: str = Depends(oauth2_scheme),
     db: Session = Depends(get_db),
 ):
     check_token(token, None)
-    item = utils.get_item_by_uuid(db, UUID(checkin.item_uuid))
-    if item is None:
-        raise HTTPException(status_code=404, detail="Item not found")
-    storage = utils.get_storage(db, checkin.storage_name)
-    if storage is None:
-        raise HTTPException(status_code=404, detail="Storage not found")
-    return utils.receive_item(db, item, storage)
+    return utils.get_storages(db)
 
 
-@app.get("/checkout/{item_uuid}", response_model=schemas.Item)
-def checkout_item(
-    item_uuid: str,
+@app.post("/item/register", response_model=schemas.Delivery)
+def add_item_with_image(
+    image: UploadFile,
     token: str = Depends(oauth2_scheme),
     db: Session = Depends(get_db),
 ):
     check_token(token, None)
-    item = utils.get_item_by_uuid(db, UUID(item_uuid))
-    if item is None:
-        raise HTTPException(status_code=404, detail="Item not found")
-    return utils.deliver_item(db, item)
-
-
-@app.post("/token")
-def verify_supporter(form_data: OAuth2PasswordRequestForm = Depends()):
-    if form_data.password != settings.shared_secret:
-        raise HTTPException(status_code=400, detail="Incorrect username or password")
-    return {
-        "access_token": oauth2_tokener.dumps("all"),
-        "token_type": "bearer",
-    }
-
-
-@app.post("/login")
-def verify_customer(
-    login_data: schemas.LoginData, db: Session = Depends(get_db)
-):  # item_uuid: str, signature: str):
-    print(login_data)
-    item = utils.get_item_by_uuid(db, UUID(login_data.item_uuid))
-    if not item:
-        raise HTTPException(status_code=404, detail="Item not found")
-    if not utils.verify_signature(item, login_data.signature):
-        raise HTTPException(status_code=400, detail="Invalid signature")
-    return {
-        "access_token": oauth2_tokener.dumps(str(item.uuid)),
-        "token_type": "bearer",
-    }
-
-
-@app.get("/token/check")
-def check_token_validity(token: str = Depends(oauth2_scheme)):
-    check_token(token, None)
+    print(image.file)
+    return False  # utils.add_item_with_image(db, image)
+
+
+# @app.post("/item/update/{item_uuid}", response_model=schemas.Delivery)
+# def update_item(
+#    item_uuid: str,
+#    data: schemas.ItemUpdate,
+#    token: str = Depends(oauth2_scheme),
+#    db: Session = Depends(get_db),
+# ):
+#    check_token(token, item_uuid)
+#    item = utils.get_item_by_uuid(db, UUID(item_uuid))
+#    if not item:
+#        raise HTTPException(status_code=404, detail="Item not found")
+#    return utils.update_item(db, item, data)
+
+
+# @app.get("/item/{item_uuid}", response_model=schemas.Delivery)
+# def get_item(
+#    item_uuid: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
+# ):
+#    item = utils.get_item_by_uuid(db, UUID(item_uuid))
+#    if not item:
+#        raise HTTPException(status_code=404, detail="Item not found")
+#    return item
+
+
+# @app.get("/items", response_model=list[schemas.Delivery])
+# def get_items(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
+#    print(token)
+#    check_token(token, None)
+#    return utils.get_stored_items(db)
+
+
+# @app.get("/tag/{tag}", response_model=schemas.Delivery)
+# def get_item_by_tag(
+#    tag: str, token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)
+# ):
+#    check_token(token, None)
+#    item = utils.get_item_by_tag(db, tag)
+#    if not item:
+#        raise HTTPException(status_code=404, detail="Item not found")
+#    return item
+
+
+# @app.get("/storage/{storage_name}", response_model=list[schemas.Delivery])
+# def get_storage(
+#    storage_name: str,
+#    token: str = Depends(oauth2_scheme),
+#    db: Session = Depends(get_db),
+# ):
+#    check_token(token, None)
+#    return utils.get_items_for_storage(db, storage_name)
+
+
+# @app.get("/storages", response_model=list[schemas.Storage])
+# def list_storages(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
+#    check_token(token, None)
+#    return utils.get_storages(db)
+
+
+# @app.post("/checkin", response_model=schemas.Delivery)
+# def checkin_item_by_uuid(
+#    checkin: schemas.ItemCheckin,
+#    token: str = Depends(oauth2_scheme),
+#    db: Session = Depends(get_db),
+# ):
+#    check_token(token, None)
+#    item = utils.get_item_by_uuid(db, UUID(checkin.item_uuid))
+#    if item is None:
+#        raise HTTPException(status_code=404, detail="Item not found")
+#    storage = utils.get_storage(db, checkin.storage_name)
+#    if storage is None:
+#        raise HTTPException(status_code=404, detail="Storage not found")
+#    return utils.receive_item(db, item, storage)
+
+
+# @app.get("/checkout/{item_uuid}", response_model=schemas.Delivery)
+# def checkout_item(
+#    item_uuid: str,
+#    token: str = Depends(oauth2_scheme),
+#    db: Session = Depends(get_db),
+# ):
+#    check_token(token, None)
+#    item = utils.get_item_by_uuid(db, UUID(item_uuid))
+#    if item is None:
+#        raise HTTPException(status_code=404, detail="Item not found")
+#    return utils.deliver_item(db, item)
diff --git a/backend/models.py b/backend/models.py
index 5a1d02397926e73b9b385462b68d6b01003d1d91..f1efc192c8876eb713272ce230e1c8b0592cf2f5 100644
--- a/backend/models.py
+++ b/backend/models.py
@@ -3,38 +3,38 @@ from uuid import uuid4
 from sqlalchemy import Column as sql_Column
 from sqlalchemy import DateTime as sql_DateTime
 from sqlalchemy import ForeignKey as sql_ForeignKey
-from sqlalchemy import Integer as sql_Integer
 from sqlalchemy import String as sql_String
 from sqlalchemy import Uuid as sql_Uuid
 from sqlalchemy.orm import relationship as sql_relationship
 from sqlalchemy.sql.functions import now as sql_now
 
+from .config import settings
 from .database import Base as db_Base
 
 
 class Item(db_Base):
     __tablename__ = "items"
-
     uuid = sql_Column(sql_Uuid, primary_key=True, default=uuid4)
-    amount = sql_Column(sql_Integer, default=1)
-    received_amount = sql_Column(sql_Integer, nullable=True, default=None)
-    created_at = sql_Column(sql_DateTime(timezone=True), server_default=sql_now())
-    received_at = sql_Column(sql_DateTime(timezone=True), nullable=True, default=None)
-
-    addressee = sql_Column(sql_String(64), nullable=True, default=None)
-    team = sql_Column(sql_String(16), nullable=True, default=None)
+    received_at = sql_Column(sql_DateTime(timezone=True), server_default=sql_now())
     images = sql_relationship("Image", back_populates="item")
-
-    deployed = sql_Column(sql_String(64), nullable=True, default=None)
     deployed_at = sql_Column(sql_DateTime(timezone=True), nullable=True, default=None)
+    storage_name = sql_Column(sql_String(16), sql_ForeignKey("store.name"))
+    stored_at = sql_relationship(
+        "Storage", back_populates="items", foreign_keys=[storage_name]
+    )
+    delivery_uuid = sql_Column(sql_Uuid, sql_ForeignKey("deliveries.uuid"))
+    part_of = sql_relationship("Delivery", back_populates="items")
 
-    verification = sql_Column(sql_String(114), nullable=True, default=None)
-    tag = sql_Column(sql_String(6), nullable=True, default=None)
 
-    storage = sql_Column(
-        sql_String(16), sql_ForeignKey("store.name"), nullable=True, default=None
-    )
-    stored_at = sql_relationship("Storage", back_populates="items")
+class Delivery(db_Base):
+    __tablename__ = "deliveries"
+
+    uuid = sql_Column(sql_Uuid, primary_key=True, default=uuid4)
+    addressee = sql_Column(sql_String(64), nullable=True, default=None)
+    team = sql_Column(sql_String(16), nullable=True, default=None)
+    verification = sql_Column(sql_String(114), nullable=True, default=None)
+    tag = sql_Column(sql_String(settings.tag_length), nullable=True, default=None)
+    items = sql_relationship("Item", back_populates="part_of")
 
 
 class Storage(db_Base):
diff --git a/backend/schemas.py b/backend/schemas.py
index 25d4a1040c630338ae41e51be72589c53a607efd..c73c301f26f4c01f05b7a8f5aec6505dac1292aa 100644
--- a/backend/schemas.py
+++ b/backend/schemas.py
@@ -11,59 +11,49 @@ class Image(BaseModel):
         orm_mode = True
 
 
-class ItemCreatePrepareShipping(BaseModel):
-    verification: str
-    addressee: Union[str, None] = None
-    team: Union[str, None] = None
+class ItemAdd(BaseModel):
+    delivery_uuid: UUID4
+    storage_name: str
 
 
-class ItemCreateByImageAtStorage(BaseModel):
-    image_uuid: UUID4
-    storage_uuid: UUID4
+class Item(ItemAdd):
+    uuid: UUID4
+    received_at: datetime
+    images: List[Image]
+    deployed_at: Union[datetime, None] = None
+    storage_name: str
+    delivery_uuid: UUID4
 
+    class Config:
+        orm_mode = True
 
-class ItemCheckin(BaseModel):
-    item_uuid: str
-    storage_name: str
-    amount: Union[int, None] = 1
 
+class Storage(BaseModel):
+    name: str
+    items: List[Item]
 
-class ItemUpdate(BaseModel):
-    addressee: Union[str, None] = None
-    team: Union[str, None] = None
-    amount: Union[int, None] = None
+    class Config:
+        orm_mode = True
 
 
-class Item(BaseModel):
-    uuid: UUID4
-    amount: int
-    created_at: datetime
-    received_at: Union[datetime, None] = None
+class DeliveryBase(BaseModel):
+    verification: Union[str, None] = None
 
+
+class DeliveryUpdate(BaseModel):
     addressee: Union[str, None] = None
     team: Union[str, None] = None
-    images: List[Image] = []
 
-    deployed: Union[str, None] = None
-    deployed_at: Union[datetime, None] = None
 
-    verification: Union[str, None] = None
+class Delivery(DeliveryBase, DeliveryUpdate):
+    uuid: UUID4
     tag: Union[str, None] = None
-
-    storage: Union[str, None] = None
+    items: List[Item]
 
     class Config:
         orm_mode = True
 
 
 class LoginData(BaseModel):
-    item_uuid: str
+    delivery_uuid: str
     signature: str
-
-
-class Storage(BaseModel):
-    name: str
-    items: List[Item]
-
-    class Config:
-        orm_mode = True
diff --git a/backend/utils.py b/backend/utils.py
index 80fb90ec971720f6f296b15c0036b6dd8815ea42..90bbd9a6669b38b96ae357642ee05c798e69cdc1 100644
--- a/backend/utils.py
+++ b/backend/utils.py
@@ -1,8 +1,9 @@
 from datetime import datetime
 from html import escape
-from secrets import token_hex
-from shutil import copyfileobj
-from tempfile import SpooledTemporaryFile
+from random import choices
+
+# from shutil import copyfileobj
+from string import digits
 
 from cryptography.exceptions import InvalidSignature
 from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PublicKey
@@ -10,120 +11,159 @@ from pydantic import UUID4
 from sqlalchemy.orm import Session
 
 from . import models, schemas
+from .config import settings
 
-
-def get_item_by_uuid(db: Session, item_uuid: UUID4):
-    return db.get(models.Item, item_uuid)
-
-
-def get_item_by_tag(db: Session, item_tag: str):
-    return db.query(models.Item).filter(models.Item.tag == item_tag).first()
-
-
-def get_storage(db: Session, storage_name: str):
-    return db.get(models.Storage, storage_name)
-
-
-def get_stored_items(db: Session):
-    return (
-        db.query(models.Item)
-        .filter(models.Item.received_at != None)  # noqa: E711
-        .filter(models.Item.deployed_at == None)  # noqa: E711
-        .order_by(models.Item.storage, models.Item.addressee)
-        .all()
-    )
-
-
-def get_items_for_storage(db: Session, storage_name: str):
-    return (
-        db.query(models.Item)
-        .filter(models.Item.storage == storage_name)
-        .filter(models.Item.received_at != None)  # noqa: E711
-        .filter(models.Item.deployed_at == None)  # noqa: E711
-        .all()
-    )
-
-
-def get_storages(db: Session):
-    return db.query(models.Storage).all()
+# from tempfile import SpooledTemporaryFile
 
 
-def prepare_item_shipping(db: Session, item: schemas.ItemCreatePrepareShipping):
-    # we want the tag to be unique.
-    # FIXME: this may never finish.
-    tag = token_hex(3)
-    while db.query(models.Item).filter(models.Item.tag == tag).count() > 0:
-        tag = token_hex(3)
-    new_item = models.Item(**item.dict(), tag=tag)
-    db.add(new_item)
-    db.commit()
-    db.refresh(new_item)
-    return new_item
+# helpers
+def generate_tag():
+    return "".join(choices(digits, k=settings.tag_length))
 
 
-def add_item_with_image(db: Session, image: SpooledTemporaryFile):
-    db_item = models.Item()
-    db.add(db_item)
-    db.commit()
-    db_image = models.Image(item_uuid=db_item.uuid)
-    db.add(db_image)
-    db.commit()
-    db.refresh(db_image)
-    print(db_item.uuid)
-    print(db_image.uuid)
-    with open(f"./images/{ db_image.uuid }", "wb") as destination:
-        try:
-            copyfileobj(image.file, destination)
-        finally:
-            image.file.close
-    return db_item
-
-
-def verify_signature(item: str, signature: str):
-    public_key = Ed448PublicKey.from_public_bytes(bytes.fromhex(item.verification))
-    print(str(item.uuid))
-    print(signature)
+def verify_signature(delivery: schemas.Delivery, data: str, signature: str):
+    public_key = Ed448PublicKey.from_public_bytes(bytes.fromhex(delivery.verification))
     try:
-        public_key.verify(bytes.fromhex(signature), bytes(str(item.uuid), "utf-8"))
+        public_key.verify(bytes.fromhex(signature), bytes(str(data), "utf-8"))
     except InvalidSignature:
         return False
     return True
 
 
-def update_item(db: Session, item: schemas.Item, data: schemas.ItemUpdate):
-    if data.addressee:
-        item.addressee = escape(data.addressee)
-    if data.team:
-        item.team = escape(data.team)
-    if data.amount:
-        item.amount = data.amount
-    db.commit()
-    db.refresh(item)
-    return item
+# main functions
+def get_image_by_uuid(db: Session, image_uuid: UUID4):
+    return db.get(models.Image, image_uuid)
 
 
-def receive_item_with_image(db: Session, item: schemas.ItemCreateByImageAtStorage):
-    new_item = models.Item(storage_uuid=item.storage_uuid)
-    db.add(new_item)
-    db.commit()
-    db.refresh(new_item)
-    new_image = models.Image(item_uuid=new_item.uuid)
-    db.add(new_image)
-    db.commit()
-    return new_item
+def get_item_by_uuid(db: Session, item_uuid: UUID4):
+    return db.get(models.Item, item_uuid)
+
 
+def get_storage_by_name(db: Session, storage_name: str):
+    storage = db.get(models.Storage, storage_name)
+    if storage:
+        storage.items = [
+            item for item in storage.items if item.deployed_at == None  # noqa: E711
+        ]
+    return storage
 
-def receive_item(db: Session, item: schemas.Item, storage: schemas.Storage):
-    item.received_at = datetime.now()
-    item.deployed_at = None
-    item.storage = storage.name
+
+def get_storages(db: Session):
+    storages = db.query(models.Storage).all()
+    for storage in storages:
+        storage.items = [
+            item for item in storage.items if item.deployed_at == None  # noqa: E711
+        ]
+    return storages
+
+
+def get_delivery_by_uuid(db: Session, delivery_uuid: UUID4):
+    delivery = db.get(models.Delivery, delivery_uuid)
+    if delivery:
+        delivery.amount = len(delivery.items)
+        delivery.items = [
+            item for item in delivery.items if item.deployed_at == None  # noqa: E711
+        ]
+    return delivery
+
+
+def get_delivery_by_tag(db: Session, delivery_tag: str):
+    delivery = (
+        db.query(models.Delivery).filter(models.Delivery.tag == delivery_tag).first()
+    )
+    if delivery:
+        delivery.amount = len(delivery.items)
+        delivery.items = [
+            item for item in delivery.items if item.deployed_at == None  # noqa: E711
+        ]
+    return delivery
+
+
+def prepare_delivery(db: Session, verification: str):
+    tag = generate_tag()
+    while db.query(models.Delivery).filter(models.Delivery.tag == tag).count() > 0:
+        tag = generate_tag()
+    delivery = models.Delivery(verification=verification, tag=tag)
+    db.add(delivery)
+    db.commit()
+    db.refresh(delivery)
+    return delivery
+
+
+def update_delivery_data(
+    db: Session, delivery_uuid: UUID4, update_data: schemas.DeliveryUpdate
+):
+    delivery = db.get(models.Delivery, delivery_uuid)
+    if delivery:
+        if update_data.addressee:
+            delivery.addressee = escape(update_data.addressee)
+        if update_data.team:
+            delivery.team = escape(update_data.team)
+        db.commit()
+        db.refresh(delivery)
+        delivery.amount = len(delivery.items)
+        delivery.items = [
+            item for item in delivery.items if item.deployed_at == None  # noqa: E711
+        ]
+        return delivery
+
+
+def add_item_for_delivery_at_storage(
+    db: Session, delivery_uuid: UUID4, storage_name: str
+):
+    delivery = db.get(models.Delivery, delivery_uuid)
+    storage = db.get(models.Storage, storage_name)
+    item = models.Item(storage_name=storage_name, stored_at=storage, part_of=delivery)
+    db.add(item)
     db.commit()
     db.refresh(item)
     return item
 
 
-def deliver_item(db: Session, item: schemas.Item):
+def deploy_item(db: Session, item_uuid: UUID4):
+    item = db.get(models.Item, item_uuid)
     item.deployed_at = datetime.now()
     db.commit()
     db.refresh(item)
     return item
+
+
+# def add_item_with_image(db: Session, image: SpooledTemporaryFile):
+#    db_item = models.Delivery()
+#    db.add(db_item)
+#    db.commit()
+#    db_image = models.Image(item_uuid=db_item.uuid)
+#    db.add(db_image)
+#    db.commit()
+#    db.refresh(db_image)
+#    print(db_item.uuid)
+#    print(db_image.uuid)
+#    with open(f"./images/{ db_image.uuid }", "wb") as destination:
+#        try:
+#            copyfileobj(image.file, destination)
+#        finally:
+#            image.file.close
+#    return db_item
+#
+#
+#
+# def update_item(db: Session, item: schemas.Delivery, data: schemas.ItemUpdate):
+#    if data.addressee:
+#        item.addressee = escape(data.addressee)
+#    if data.team:
+#        item.team = escape(data.team)
+#    if data.amount:
+#        item.amount = data.amount
+#    db.commit()
+#    db.refresh(item)
+#    return item
+#
+#
+# def receive_item_with_image(db: Session, item: schemas.ItemCreateByImageAtStorage):
+#    new_item = models.Delivery(storage_uuid=item.storage_uuid)
+#    db.add(new_item)
+#    db.commit()
+#    db.refresh(new_item)
+#    new_image = models.Image(item_uuid=new_item.uuid)
+#    db.add(new_image)
+#    db.commit()