diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala b/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala
index e007b1af..eba07e84 100644
--- a/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala
+++ b/modules/backend/src/main/scala/docspell/backend/ops/OOrganization.scala
@@ -28,8 +28,10 @@ trait OOrganization[F[_]] {
 
   def findAllPersonRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]]
 
+  /** Add a new person with their contacts. The additional organization is ignored. */
   def addPerson(s: PersonAndContacts): F[AddResult]
 
+  /** Update a person with their contacts. The additional organization is ignored. */
   def updatePerson(s: PersonAndContacts): F[AddResult]
 
   def deleteOrg(orgId: Ident, collective: Ident): F[AddResult]
@@ -41,7 +43,11 @@ object OOrganization {
 
   case class OrgAndContacts(org: ROrganization, contacts: Seq[RContact])
 
-  case class PersonAndContacts(person: RPerson, contacts: Seq[RContact])
+  case class PersonAndContacts(
+      person: RPerson,
+      org: Option[ROrganization],
+      contacts: Seq[RContact]
+  )
 
   def apply[F[_]: Effect](store: Store[F]): Resource[F, OOrganization[F]] =
     Resource.pure[F, OOrganization[F]](new OOrganization[F] {
@@ -79,14 +85,14 @@ object OOrganization {
       ): F[Vector[PersonAndContacts]] =
         store
           .transact(QOrganization.findPersonAndContact(account.collective, query, _.name))
-          .map({ case (person, cont) => PersonAndContacts(person, cont) })
+          .map({ case (person, org, cont) => PersonAndContacts(person, org, cont) })
           .compile
           .toVector
 
       def findPerson(account: AccountId, persId: Ident): F[Option[PersonAndContacts]] =
         store
           .transact(QOrganization.getPersonAndContact(account.collective, persId))
-          .map(_.map({ case (org, cont) => PersonAndContacts(org, cont) }))
+          .map(_.map({ case (pers, org, cont) => PersonAndContacts(pers, org, cont) }))
 
       def findAllPersonRefs(
           account: AccountId,
diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml
index db8a440d..70d7c979 100644
--- a/modules/restapi/src/main/resources/docspell-openapi.yml
+++ b/modules/restapi/src/main/resources/docspell-openapi.yml
@@ -4833,6 +4833,8 @@ components:
           format: ident
         name:
           type: string
+        organization:
+          $ref: "#/components/schemas/IdName"
         address:
           $ref: "#/components/schemas/Address"
         contacts:
diff --git a/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala b/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala
index b17ca5f7..bdba7bf6 100644
--- a/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala
+++ b/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala
@@ -414,15 +414,16 @@ trait Conversions {
   }
 
   def mkPerson(v: OOrganization.PersonAndContacts): Person = {
-    val ro = v.person
+    val rp = v.person
     Person(
-      ro.pid,
-      ro.name,
-      Address(ro.street, ro.zip, ro.city, ro.country),
+      rp.pid,
+      rp.name,
+      v.org.map(o => IdName(o.oid, o.name)),
+      Address(rp.street, rp.zip, rp.city, rp.country),
       v.contacts.map(mkContact).toList,
-      ro.notes,
-      ro.concerning,
-      ro.created
+      rp.notes,
+      rp.concerning,
+      rp.created
     )
   }
 
@@ -433,7 +434,7 @@ trait Conversions {
       now  <- Timestamp.current[F]
       pid  <- Ident.randomId[F]
       cont <- contacts(pid)
-      org = RPerson(
+      pers = RPerson(
         pid,
         cid,
         v.name,
@@ -444,9 +445,10 @@ trait Conversions {
         v.notes,
         v.concerning,
         now,
-        now
+        now,
+        v.organization.map(_.id)
       )
-    } yield OOrganization.PersonAndContacts(org, cont)
+    } yield OOrganization.PersonAndContacts(pers, None, cont)
   }
 
   def changePerson[F[_]: Sync](
@@ -458,7 +460,7 @@ trait Conversions {
     for {
       now  <- Timestamp.current[F]
       cont <- contacts(v.id)
-      org = RPerson(
+      pers = RPerson(
         v.id,
         cid,
         v.name,
@@ -469,9 +471,10 @@ trait Conversions {
         v.notes,
         v.concerning,
         v.created,
-        now
+        now,
+        v.organization.map(_.id)
       )
-    } yield OOrganization.PersonAndContacts(org, cont)
+    } yield OOrganization.PersonAndContacts(pers, None, cont)
   }
 
   // contact
diff --git a/modules/store/src/main/resources/db/migration/h2/V1.14.0__person_org.sql b/modules/store/src/main/resources/db/migration/h2/V1.14.0__person_org.sql
new file mode 100644
index 00000000..82832cc8
--- /dev/null
+++ b/modules/store/src/main/resources/db/migration/h2/V1.14.0__person_org.sql
@@ -0,0 +1,7 @@
+ALTER TABLE "person"
+ADD COLUMN "oid" varchar(254);
+
+ALTER TABLE "person"
+ADD CONSTRAINT fk_person_organization
+FOREIGN KEY ("oid")
+REFERENCES "organization"("oid");
diff --git a/modules/store/src/main/resources/db/migration/mariadb/V1.14.0__person_org.sql b/modules/store/src/main/resources/db/migration/mariadb/V1.14.0__person_org.sql
new file mode 100644
index 00000000..86b867ad
--- /dev/null
+++ b/modules/store/src/main/resources/db/migration/mariadb/V1.14.0__person_org.sql
@@ -0,0 +1,7 @@
+ALTER TABLE `person`
+ADD COLUMN `oid` varchar(254);
+
+ALTER TABLE `person`
+ADD CONSTRAINT fk_person_organization
+FOREIGN KEY (`oid`)
+REFERENCES `organization`(`oid`);
diff --git a/modules/store/src/main/resources/db/migration/postgresql/V1.14.0__person_org.sql b/modules/store/src/main/resources/db/migration/postgresql/V1.14.0__person_org.sql
new file mode 100644
index 00000000..82832cc8
--- /dev/null
+++ b/modules/store/src/main/resources/db/migration/postgresql/V1.14.0__person_org.sql
@@ -0,0 +1,7 @@
+ALTER TABLE "person"
+ADD COLUMN "oid" varchar(254);
+
+ALTER TABLE "person"
+ADD CONSTRAINT fk_person_organization
+FOREIGN KEY ("oid")
+REFERENCES "organization"("oid");
diff --git a/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala b/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala
index 50c0d2f2..d0234973 100644
--- a/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala
+++ b/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala
@@ -41,7 +41,7 @@ object QOrganization {
         Seq.empty
     })
 
-    (selectSimple(cols, from, and(q)) ++ orderBy(order(OC).f))
+    (selectSimple(cols, from, and(q)) ++ orderBy(order(OC).prefix("o").f))
       .query[(ROrganization, Option[RContact])]
       .stream
       .groupAdjacentBy(_._1)
@@ -82,17 +82,21 @@ object QOrganization {
       coll: Ident,
       query: Option[String],
       order: PC.type => Column
-  ): Stream[ConnectionIO, (RPerson, Vector[RContact])] = {
+  ): Stream[ConnectionIO, (RPerson, Option[ROrganization], Vector[RContact])] = {
     val pColl  = PC.cid.prefix("p")
     val pName  = RPerson.Columns.name.prefix("p")
     val pNotes = RPerson.Columns.notes.prefix("p")
     val pId    = RPerson.Columns.pid.prefix("p")
     val cPers  = RContact.Columns.personId.prefix("c")
     val cVal   = RContact.Columns.value.prefix("c")
+    val oId    = ROrganization.Columns.oid.prefix("o")
+    val pOid   = RPerson.Columns.oid.prefix("p")
 
-    val cols = RPerson.Columns.all.map(_.prefix("p")) ++ RContact.Columns.all
-      .map(_.prefix("c"))
+    val cols = RPerson.Columns.all.map(_.prefix("p")) ++
+      ROrganization.Columns.all.map(_.prefix("o")) ++
+      RContact.Columns.all.map(_.prefix("c"))
     val from = RPerson.table ++ fr"p LEFT JOIN" ++
+      ROrganization.table ++ fr"o ON" ++ pOid.is(oId) ++ fr"LEFT JOIN" ++
       RContact.table ++ fr"c ON" ++ cPers.is(pId)
 
     val q = Seq(pColl.is(coll)) ++ (query match {
@@ -103,38 +107,44 @@ object QOrganization {
         Seq.empty
     })
 
-    (selectSimple(cols, from, and(q)) ++ orderBy(order(PC).f))
-      .query[(RPerson, Option[RContact])]
+    (selectSimple(cols, from, and(q)) ++ orderBy(order(PC).prefix("p").f))
+      .query[(RPerson, Option[ROrganization], Option[RContact])]
       .stream
       .groupAdjacentBy(_._1)
-      .map({ case (ro, chunk) =>
-        val cs = chunk.toVector.flatMap(_._2)
-        (ro, cs)
+      .map({ case (rp, chunk) =>
+        val cs = chunk.toVector.flatMap(_._3)
+        val ro = chunk.map(_._2).head.flatten
+        (rp, ro, cs)
       })
   }
 
   def getPersonAndContact(
       coll: Ident,
       persId: Ident
-  ): ConnectionIO[Option[(RPerson, Vector[RContact])]] = {
+  ): ConnectionIO[Option[(RPerson, Option[ROrganization], Vector[RContact])]] = {
     val pColl = PC.cid.prefix("p")
     val pId   = RPerson.Columns.pid.prefix("p")
     val cPers = RContact.Columns.personId.prefix("c")
+    val oId   = ROrganization.Columns.oid.prefix("o")
+    val pOid  = RPerson.Columns.oid.prefix("p")
 
-    val cols = RPerson.Columns.all.map(_.prefix("p")) ++ RContact.Columns.all
-      .map(_.prefix("c"))
+    val cols = RPerson.Columns.all.map(_.prefix("p")) ++
+      ROrganization.Columns.all.map(_.prefix("o")) ++
+      RContact.Columns.all.map(_.prefix("c"))
     val from = RPerson.table ++ fr"p LEFT JOIN" ++
+      ROrganization.table ++ fr"o ON" ++ pOid.is(oId) ++ fr"LEFT JOIN" ++
       RContact.table ++ fr"c ON" ++ cPers.is(pId)
 
     val q = and(pColl.is(coll), pId.is(persId))
 
     selectSimple(cols, from, q)
-      .query[(RPerson, Option[RContact])]
+      .query[(RPerson, Option[ROrganization], Option[RContact])]
       .stream
       .groupAdjacentBy(_._1)
-      .map({ case (ro, chunk) =>
-        val cs = chunk.toVector.flatMap(_._2)
-        (ro, cs)
+      .map({ case (rp, chunk) =>
+        val cs = chunk.toVector.flatMap(_._3)
+        val ro = chunk.map(_._2).head.flatten
+        (rp, ro, cs)
       })
       .compile
       .last
diff --git a/modules/store/src/main/scala/docspell/store/records/RPerson.scala b/modules/store/src/main/scala/docspell/store/records/RPerson.scala
index 87abb00c..b59d4cf4 100644
--- a/modules/store/src/main/scala/docspell/store/records/RPerson.scala
+++ b/modules/store/src/main/scala/docspell/store/records/RPerson.scala
@@ -21,7 +21,8 @@ case class RPerson(
     notes: Option[String],
     concerning: Boolean,
     created: Timestamp,
-    updated: Timestamp
+    updated: Timestamp,
+    oid: Option[Ident]
 ) {}
 
 object RPerson {
@@ -42,6 +43,7 @@ object RPerson {
     val concerning = Column("concerning")
     val created    = Column("created")
     val updated    = Column("updated")
+    val oid        = Column("oid")
     val all = List(
       pid,
       cid,
@@ -53,7 +55,8 @@ object RPerson {
       notes,
       concerning,
       created,
-      updated
+      updated,
+      oid
     )
   }
 
@@ -63,7 +66,7 @@ object RPerson {
     val sql = insertRow(
       table,
       all,
-      fr"${v.pid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.concerning},${v.created},${v.updated}"
+      fr"${v.pid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.concerning},${v.created},${v.updated},${v.oid}"
     )
     sql.update.run
   }
@@ -82,6 +85,7 @@ object RPerson {
           country.setTo(v.country),
           concerning.setTo(v.concerning),
           notes.setTo(v.notes),
+          oid.setTo(v.oid),
           updated.setTo(now)
         )
       )