diff --git a/deploy/saneUrl/index.js b/deploy/saneUrl/index.js
index 4bfcf3740c70b47b9f746f9fcda2170c5461643a..2e9ab0b76528b999720781f7ff9cc913891f478d 100644
--- a/deploy/saneUrl/index.js
+++ b/deploy/saneUrl/index.js
@@ -27,6 +27,8 @@ const passthrough = (_, __, next) => next()
 
 const acceptHtmlProg = /text\/html/i
 
+const REAL_HOSTNAME = `${HOSTNAME}${HOST_PATHNAME || ''}/`
+
 router.get('/:name', async (req, res) => {
   const { name } = req.params
   const { headers } = req
@@ -34,7 +36,6 @@ router.get('/:name', async (req, res) => {
   const redirectFlag = acceptHtmlProg.test(headers['accept'])
     
   try {
-    const REAL_HOSTNAME = `${HOSTNAME}${HOST_PATHNAME || ''}/`
 
     const json = await NotExactlyPromiseAny([
       ProxyStore.StaticGet(depStore, req, name),
diff --git a/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts b/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts
index 956f23c080c1929b07fc62159a42024c68334490..8c9a11566b9f7f27350a684cc9ffc3976525c32e 100644
--- a/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts
+++ b/src/atlasComponents/userAnnotations/singleAnnotationUnit/singleAnnotationUnit.component.ts
@@ -48,8 +48,8 @@ export class SingleAnnotationUnit implements OnDestroy, AfterViewInit{
     this.chSubs.push(
       this.formGrp.valueChanges.subscribe(value => {
         const { name, desc, spaceId } = value
-        this.managedAnnotation.setName(name)
-        this.managedAnnotation.setDesc(desc)
+        this.managedAnnotation.name = name
+        this.managedAnnotation.desc = desc
       })
     )
 
diff --git a/src/atlasComponents/userAnnotations/tools/line.ts b/src/atlasComponents/userAnnotations/tools/line.ts
index 606c155f3e995bbf3bba85d6b82cb4040ae7a76e..bea53cdf42b49e494e9f3419813f4b9178dc3b99 100644
--- a/src/atlasComponents/userAnnotations/tools/line.ts
+++ b/src/atlasComponents/userAnnotations/tools/line.ts
@@ -45,7 +45,7 @@ export class Line extends IAnnotationGeometry{
       })
     if (!this.points[0]) this.points[0] = point
     else this.points[1] = point
-    this.sendUpdateSignal()
+    this.changed()
     return point
   }
 
@@ -172,11 +172,7 @@ export class Line extends IAnnotationGeometry{
     for (const p of this.points){
       p.translate(x, y, z)
     }
-    this.sendUpdateSignal()
-  }
-
-  private sendUpdateSignal(){
-    this.updateSignal$.next(this.toString())
+    this.changed()
   }
 }
 
@@ -244,7 +240,7 @@ export class ToolLine extends AbsToolClass<Line> implements IAnnotationTools, On
          * it only has a single point, and should be removed
          */
         if (this.selectedLine) {
-          this.removeAnnotation(this.selectedLine.id)
+          this.removeAnnotation(this.selectedLine)
         }
         this.selectedLine = null
       }),
@@ -311,14 +307,4 @@ export class ToolLine extends AbsToolClass<Line> implements IAnnotationTools, On
   ngOnDestroy(){
     this.subs.forEach(s => s.unsubscribe())
   }
-
-  removeAnnotation(id: string){
-    const idx = this.managedAnnotations.findIndex(ann => ann.id === id)
-    if (idx < 0) {
-      return
-    }
-    this.managedAnnotations.splice(idx, 1)
-    this.managedAnnotations$.next(this.managedAnnotations)
-  }
-
 }
diff --git a/src/atlasComponents/userAnnotations/tools/point.ts b/src/atlasComponents/userAnnotations/tools/point.ts
index af1543fed9b100ecabda6373bf4055b685c580f7..1db473a6713ed78b82c0d12c4a34acf65f13bb84 100644
--- a/src/atlasComponents/userAnnotations/tools/point.ts
+++ b/src/atlasComponents/userAnnotations/tools/point.ts
@@ -95,7 +95,7 @@ export class Point extends IAnnotationGeometry {
     this.x += x
     this.y += y
     this.z += z
-    this.updateSignal$.next(this.toString())
+    this.changed()
   }
 }
 
@@ -177,20 +177,6 @@ export class ToolPoint extends AbsToolClass<Point> implements IAnnotationTools,
     )
   }
 
-  /**
-   * @description remove managed annotation via id
-   * @param id id of annotation
-   */
-  removeAnnotation(id: string) {
-    const idx = this.managedAnnotations.findIndex(ann => id === ann.id)
-    if (idx < 0){
-      throw new Error(`cannot find point idx ${idx}`)
-      return
-    }
-    this.managedAnnotations.splice(idx, 1)
-    this.managedAnnotations$.next(this.managedAnnotations)
-  }
-
   onMouseMoveRenderPreview(pos: [number, number, number]) {
     return [{
       id: `${ToolPoint.PREVIEW_ID}_0`,
diff --git a/src/atlasComponents/userAnnotations/tools/poly.ts b/src/atlasComponents/userAnnotations/tools/poly.ts
index 2cd9285b256119f8ec112825b96fc615a6eea407..b7929b5dfe77e378ae6a52c2f5c67d5333547025 100644
--- a/src/atlasComponents/userAnnotations/tools/poly.ts
+++ b/src/atlasComponents/userAnnotations/tools/poly.ts
@@ -37,7 +37,7 @@ export class Polygon extends IAnnotationGeometry{
     this.edges = this.edges.filter(([ idx1, idx2 ]) => idx1 !== ptIdx && idx2 !== ptIdx)
     this.points.splice(ptIdx, 1)
 
-    this.sendUpdateSignal()
+    this.changed()
   }
 
   public addPoint(p: Point | {x: number, y: number, z: number}, linkTo?: Point): Point {
@@ -56,7 +56,7 @@ export class Polygon extends IAnnotationGeometry{
     if (!this.hasPoint(pointToBeAdded)) {
       this.points.push(pointToBeAdded)
       const sub = pointToBeAdded.updateSignal$.subscribe(
-        () => this.sendUpdateSignal()
+        () => this.changed()
       )
       this.ptWkMp.set(pointToBeAdded, {
         onremove: () => {
@@ -71,7 +71,7 @@ export class Polygon extends IAnnotationGeometry{
       ] as [number, number]
       this.edges.push(newEdge)
     }
-    this.sendUpdateSignal()
+    this.changed()
     return pointToBeAdded
   }
 
@@ -209,15 +209,11 @@ export class Polygon extends IAnnotationGeometry{
     this.edges = edges
   }
 
-  private sendUpdateSignal(){
-    this.updateSignal$.next(this.toString())
-  }
-
   public translate(x: number, y: number, z: number) {
     for (const p of this.points){
       p.translate(x, y, z)
     }
-    this.sendUpdateSignal()
+    this.changed()
   }
 }
 
@@ -307,7 +303,7 @@ export class ToolPolygon extends AbsToolClass<Polygon> implements IAnnotationToo
            * if edges < 3, discard poly
            */
           if (edges.length < 3) {
-            this.removeAnnotation(this.selectedPoly.id)
+            this.removeAnnotation(this.selectedPoly)
           }
         }
 
@@ -404,15 +400,6 @@ export class ToolPolygon extends AbsToolClass<Polygon> implements IAnnotationToo
     )
   }
 
-  removeAnnotation(id: string) {
-    const idx = this.managedAnnotations.findIndex(ann => ann.id === id)
-    if (idx < 0) {
-      return
-    }
-    this.managedAnnotations.splice(idx, 1)
-    this.managedAnnotations$.next(this.managedAnnotations)
-  }
-
   ngOnDestroy(){
     if (this.subs.length > 0) this.subs.pop().unsubscribe()
   }
diff --git a/src/atlasComponents/userAnnotations/tools/service.ts b/src/atlasComponents/userAnnotations/tools/service.ts
index 8185ed4b6177cb3688ca381c87a4c7a05961ada4..b459ad65f7ae3f64afb99ba5346a14481ffba8f2 100644
--- a/src/atlasComponents/userAnnotations/tools/service.ts
+++ b/src/atlasComponents/userAnnotations/tools/service.ts
@@ -697,8 +697,8 @@ export class ModularUserAnnotationToolService implements OnDestroy{
 
         // potentially overwriting existing name and desc...
         // maybe should show warning?
-        existingAnn.setName(json.name)
-        existingAnn.setDesc(json.desc)
+        existingAnn.name = json.name
+        existingAnn.desc = json.desc
         return existingAnn
       } else {
         const { id, name, desc } = json
@@ -708,8 +708,8 @@ export class ModularUserAnnotationToolService implements OnDestroy{
     } else {
       const metadata = this.metadataMap.get(returnObj.id)
       if (returnObj && metadata) {
-        returnObj.setName(metadata?.name || null)
-        returnObj.setDesc(metadata?.desc || null)
+        returnObj.name = metadata?.name || null
+        returnObj.desc = metadata?.desc || null
         this.metadataMap.delete(returnObj.id)
       }
     }
diff --git a/src/atlasComponents/userAnnotations/tools/type.spec.ts b/src/atlasComponents/userAnnotations/tools/type.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f4b28738913465c7eda8ee898f28fdc724dbf016
--- /dev/null
+++ b/src/atlasComponents/userAnnotations/tools/type.spec.ts
@@ -0,0 +1,166 @@
+import { Subject, Subscription } from "rxjs"
+import { AbsToolClass, IAnnotationEvents, IAnnotationGeometry, TAnnotationEvent } from "./type"
+
+class TmpCls extends IAnnotationGeometry{
+  getNgAnnotationIds(){
+    return []
+  }
+  toNgAnnotation() {
+    return []
+  }
+  toJSON() {
+    return {}
+  }
+  toString() {
+    return ''
+  }
+  toSands(){
+    return {} as any
+  }
+}
+
+class TmpToolCls extends AbsToolClass<TmpCls> {
+  iconClass = ''
+  name: 'tmplClsTool'
+  subs = []
+  onMouseMoveRenderPreview() {
+    return []
+  }
+
+  protected managedAnnotations: TmpCls[] = []
+  public managedAnnotations$ = new Subject<TmpCls[]>()
+}
+
+describe('> types.ts', () => {
+  describe('> AbsToolClass', () => {
+    let tool: TmpToolCls
+    let ann: TmpCls
+    let managedAnn: jasmine.Spy
+    const subs: Subscription[] = []
+
+    beforeEach(() => {
+      const ev$ = new Subject<TAnnotationEvent<keyof IAnnotationEvents>>()
+      tool = new TmpToolCls(ev$, () => {})
+      ann = new TmpCls()
+      managedAnn = jasmine.createSpy('managedannspy')
+      subs.push(
+        tool.managedAnnotations$.subscribe(managedAnn)
+      )
+    })
+
+    afterEach(() => {
+      managedAnn.calls.reset()
+      while(subs.length) subs.pop().unsubscribe()
+    })
+
+    it('> shuld init just fine', () => {
+      expect(true).toEqual(true)
+    })
+    describe('> managedAnnotations$', () => {
+      describe('> on point add', () => {
+        it('> should emit new managedannotations', () => {
+          tool.addAnnotation(ann)
+          expect(managedAnn).toHaveBeenCalled()
+          expect(managedAnn).toHaveBeenCalledTimes(1)
+          const firstCallArgs = managedAnn.calls.allArgs()[0]
+          const firstArg = firstCallArgs[0]
+          expect(firstArg).toEqual([ann])
+        })
+      })
+      describe('> on point update', () => {
+        it('> should emit new managedannotations', () => {
+          tool.addAnnotation(ann)
+          ann.name = 'blabla'
+          expect(managedAnn).toHaveBeenCalledTimes(2)
+          const firstCallArgs = managedAnn.calls.allArgs()[0]
+          const secondCallArgs = managedAnn.calls.allArgs()[1]
+          expect(firstCallArgs).toEqual(secondCallArgs)
+        })
+      })
+      describe('> on point rm', () => {
+        it('> managed annotation === 0', () => {
+          tool.addAnnotation(ann)
+
+          const firstCallArgs = managedAnn.calls.allArgs()[0]
+          const subManagedAnn0 = firstCallArgs[0]
+          expect(subManagedAnn0.length).toEqual(1)
+
+          ann.remove()
+          expect(managedAnn).toHaveBeenCalledTimes(2)
+
+          const secondCallArgs = managedAnn.calls.allArgs()[1]
+          const subManagedAnn1 = secondCallArgs[0]
+          expect(subManagedAnn1.length).toEqual(0)
+        })
+        it('> does not trigger after rm', () => {
+          tool.addAnnotation(ann)
+          ann.remove()
+          ann.name = 'blabla'
+          expect(managedAnn).toHaveBeenCalledTimes(2)
+        })
+      })
+    })
+  })
+
+  describe('> IAnnotationGeometry', () => {
+    it('> can be init fine', () => {
+      new TmpCls()
+      expect(true).toBe(true)
+    })
+
+    describe('> updateSignal$', () => {
+      class TmpCls extends IAnnotationGeometry{
+        getNgAnnotationIds(){
+          return []
+        }
+        toNgAnnotation() {
+          return []
+        }
+        toJSON() {
+          return {}
+        }
+        toString() {
+          return `${this.name || ''}:${this.desc || ''}`
+        }
+        toSands(){
+          return {} as any
+        }
+      }
+
+      let tmp: TmpCls
+      let subs: Subscription[] = []
+      let updateStub: jasmine.Spy
+      beforeEach(() => {
+        tmp = new TmpCls()
+        updateStub = jasmine.createSpy('updateSpy')
+        subs.push(
+          tmp.updateSignal$.subscribe(
+            val => updateStub(val)
+          )
+        )
+      })
+      afterEach(() => {
+        while(subs.length) subs.pop().unsubscribe()
+        updateStub.calls.reset()
+      })
+      it('> is fired on setting name', () => {
+        tmp.name = 'test'
+        expect(updateStub).toHaveBeenCalled()
+        expect(updateStub).toHaveBeenCalledTimes(1)
+      })
+
+      it('> is fired on setting desc', () => {
+        tmp.desc = 'testdesc'
+        expect(updateStub).toHaveBeenCalled()
+        expect(updateStub).toHaveBeenCalledTimes(1)
+      })
+
+      it('> should be fired even if same string', () => {
+
+        tmp.name = null
+        tmp.name = undefined
+        expect(updateStub).toHaveBeenCalledTimes(2)
+      })
+    })
+  })
+})
diff --git a/src/atlasComponents/userAnnotations/tools/type.ts b/src/atlasComponents/userAnnotations/tools/type.ts
index e74f0ca8ee389775b93f49836a4f504ab88ccfec..85a4c2e0f6783a024017a34fc0b50588a89ccfcd 100644
--- a/src/atlasComponents/userAnnotations/tools/type.ts
+++ b/src/atlasComponents/userAnnotations/tools/type.ts
@@ -18,9 +18,8 @@ export abstract class AbsToolClass<T extends IAnnotationGeometry> {
   public abstract name: string
   public abstract iconClass: string
 
-  public abstract removeAnnotation(id: string): void
   public abstract managedAnnotations$: Subject<T[]>
-  protected abstract managedAnnotations: T[] = []
+  protected managedAnnotations: T[] = []
 
   abstract subs: Subscription[]
   protected space: TBaseAnnotationGeomtrySpec['space']
@@ -158,10 +157,26 @@ export abstract class AbsToolClass<T extends IAnnotationGeometry> {
   public addAnnotation(geom: T) {
     const found = this.managedAnnotations.find(ann => ann.id === geom.id)
     if (found) found.remove()
-    geom.remove = () => this.removeAnnotation(geom.id)
+    const sub = geom.updateSignal$.subscribe(() => {
+      this.managedAnnotations$.next(this.managedAnnotations)
+    })
+    geom.remove = () => {
+      this.removeAnnotation(geom)
+      sub.unsubscribe()
+    }
     this.managedAnnotations.push(geom)
     this.managedAnnotations$.next(this.managedAnnotations)
   }
+
+  public removeAnnotation(geom: T) {
+    const idx = this.managedAnnotations.findIndex(ann => ann.id === geom.id)
+    if (idx < 0) {
+      console.warn(`removeAnnotation error: cannot annotation with id: ${geom.id}`)
+      return
+    }
+    this.managedAnnotations.splice(idx, 1)
+    this.managedAnnotations$.next(this.managedAnnotations)
+  }
 }
 
 export type TToolType = 'selecting' | 'drawing' | 'deletion'
@@ -276,8 +291,25 @@ export abstract class Highlightable {
 export abstract class IAnnotationGeometry extends Highlightable {
   public id: string
   
-  public name: string
-  public desc: string
+  private _name: string
+  set name(val: string) {
+    if (val === this._name) return
+    this._name = val
+    this.changed()
+  }
+  get name(): string {
+    return this._name
+  }
+
+  private _desc: string
+  set desc(val: string) {
+    if (val === this._desc) return
+    this._desc = val
+    this.changed()
+  }
+  get desc(): string {
+    return this._desc
+  }
 
   public space: TBaseAnnotationGeomtrySpec['space']
 
@@ -290,7 +322,13 @@ export abstract class IAnnotationGeometry extends Highlightable {
   public remove() {
     throw new Error(`The remove method needs to be overwritten by the tool manager`)
   }
-  public updateSignal$ = new Subject()
+
+  private _updateSignal$ = new Subject()
+
+  public updateSignal$ = this._updateSignal$.asObservable()
+  protected changed(){
+    this._updateSignal$.next(Date.now())
+  }
 
   constructor(spec?: TBaseAnnotationGeomtrySpec){
     super()
@@ -299,15 +337,6 @@ export abstract class IAnnotationGeometry extends Highlightable {
     this.name = spec?.name
     this.desc = spec?.desc
   }
-
-  setName(name: string) {
-    this.name = name
-    this.updateSignal$.next(this.toString())
-  }
-  setDesc(desc: string) {
-    this.desc = desc
-    this.updateSignal$.next(this.toString())
-  }
 }
 
 export interface IAnnotationTools {