Index: reactapp/package-lock.json
===================================================================
--- reactapp/package-lock.json	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ reactapp/package-lock.json	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -12,4 +12,5 @@
         "@testing-library/react": "^13.3.0",
         "@testing-library/user-event": "^13.5.0",
+        "jsog": "^1.0.7",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
@@ -11226,4 +11227,9 @@
       }
     },
+    "node_modules/jsog": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/jsog/-/jsog-1.0.7.tgz",
+      "integrity": "sha512-9IA6ZY6g5rSgRTvHO7B4Ro9LGGqJEPXdKRkvPohmzdk777fldQ3rjbUkmiIG3gxswLi2ZiAKsdgqfs+zMwmRcg=="
+    },
     "node_modules/json-parse-even-better-errors": {
       "version": "2.3.1",
@@ -24734,4 +24740,9 @@
       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
     },
+    "jsog": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/jsog/-/jsog-1.0.7.tgz",
+      "integrity": "sha512-9IA6ZY6g5rSgRTvHO7B4Ro9LGGqJEPXdKRkvPohmzdk777fldQ3rjbUkmiIG3gxswLi2ZiAKsdgqfs+zMwmRcg=="
+    },
     "json-parse-even-better-errors": {
       "version": "2.3.1",
Index: reactapp/package.json
===================================================================
--- reactapp/package.json	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ reactapp/package.json	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -7,4 +7,5 @@
     "@testing-library/react": "^13.3.0",
     "@testing-library/user-event": "^13.5.0",
+    "jsog": "^1.0.7",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
Index: reactapp/src/App.css
===================================================================
--- reactapp/src/App.css	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ reactapp/src/App.css	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -2,37 +2,2 @@
   text-align: center;
 }
-
-.App-logo {
-  height: 40vmin;
-  pointer-events: none;
-}
-
-@media (prefers-reduced-motion: no-preference) {
-  .App-logo {
-    animation: App-logo-spin infinite 20s linear;
-  }
-}
-
-.App-header {
-  background-color: #282c34;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  font-size: calc(10px + 2vmin);
-  color: white;
-}
-
-.App-link {
-  color: #61dafb;
-}
-
-@keyframes App-logo-spin {
-  from {
-    transform: rotate(0deg);
-  }
-  to {
-    transform: rotate(360deg);
-  }
-}
Index: reactapp/src/App.js
===================================================================
--- reactapp/src/App.js	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ reactapp/src/App.js	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -4,13 +4,5 @@
   return (
     <div>
-      <h1>Main App Page</h1>
-      <nav
-        style={{
-          borderBottom: "solid 1px",
-          paddingBottom: "1rem",
-        }}
-      >
-        <Link to="/professor">Professor</Link>
-      </nav>
+      <h1>profesori.mk</h1>
       <Outlet />
     </div>
Index: reactapp/src/Components/OpinionTree.js
===================================================================
--- reactapp/src/Components/OpinionTree.js	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ reactapp/src/Components/OpinionTree.js	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -1,9 +1,14 @@
 function OpinionTree({ professor }) {
-  function displayChildPosts(post) {
-    if (post == null) return;
+  var renderedOpinionIds = [];
+  var postCount; // za da ne go pokazuva ispod postot
+
+  function displayChildPosts(child) {
+    if (child == null) return;
+    postCount = renderedOpinionIds.push(child.postId);
     return (
-      <div key={post.postId}>
-        <p>Содржина: {post.content}</p>
-        {post.children.map((child) => displayChildPosts(child))}
+      <div key={child.postId}>
+        <p>{child.author.username} реплицирал</p>
+        <p>Содржина: {child.content}</p>
+        {child.children.map((childOfChild) => displayChildPosts(childOfChild))}
       </div>
     );
@@ -13,10 +18,13 @@
     <div className="opinionTree">
       {professor.relatedOpinions.map((opinion) => {
-        if (opinion.hasOwnProperty("title")) {
+        if (!renderedOpinionIds.includes(opinion.postId)) {
+          postCount = renderedOpinionIds.push(opinion.postId);
           return (
             <div key={opinion.postId}>
+              <p>{opinion.author.username} напишал</p>
               <p>Наслов: {opinion.title}</p>
               <p>Содржина: {opinion.content}</p>
               {opinion.children.map((child) => displayChildPosts(child))}
+              <hr />
             </div>
           );
Index: reactapp/src/Pages/Professor.js
===================================================================
--- reactapp/src/Pages/Professor.js	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ reactapp/src/Pages/Professor.js	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -1,4 +1,5 @@
 import React, { useEffect, useState } from "react";
 import { Outlet, useParams } from "react-router-dom";
+import JSOG from "jsog";
 import OpinionTree from "../Components/OpinionTree";
 
@@ -15,6 +16,8 @@
       try {
         const response = await fetch(url);
-        const json = await response.json();
-        setProfessor(json);
+        var cyclicGraph = await response.json();
+        var jsogStructure = JSOG.encode(cyclicGraph); // has { '@ref': 'ID' } links instead of cycles
+        cyclicGraph = JSOG.decode(jsogStructure);
+        setProfessor(cyclicGraph);
         setLoaded(true);
       } catch (error) {
Index: springapp/pom.xml
===================================================================
--- springapp/pom.xml	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ springapp/pom.xml	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -57,4 +57,10 @@
     		<version>2.7.2</version>
 		</dependency>
+		<dependency>
+			<groupId>com.voodoodyne.jackson.jsog</groupId>
+			<artifactId>jackson-jsog</artifactId>
+			<version>1.1.2</version>
+			<scope>compile</scope>
+		</dependency>
 	</dependencies>
 
Index: springapp/src/main/java/mk/profesori/springapp/Model/CustomUserDetails.java
===================================================================
--- springapp/src/main/java/mk/profesori/springapp/Model/CustomUserDetails.java	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ springapp/src/main/java/mk/profesori/springapp/Model/CustomUserDetails.java	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -23,5 +23,5 @@
 
 import com.fasterxml.jackson.annotation.JsonIdentityInfo;
-import com.fasterxml.jackson.annotation.ObjectIdGenerators;
+import com.voodoodyne.jackson.jsog.JSOGGenerator;
 
 import lombok.EqualsAndHashCode;
@@ -35,5 +35,5 @@
 @NoArgsConstructor
 @Entity
-@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
+@JsonIdentityInfo(generator = JSOGGenerator.class)
 public class CustomUserDetails implements UserDetails {
 
@@ -45,5 +45,5 @@
     private String username;
     private String email;
-    private String password;
+    private String password; // TODO dont expose password in api
     @Enumerated(EnumType.STRING)
     private UserRole userRole;
Index: springapp/src/main/java/mk/profesori/springapp/Model/Post.java
===================================================================
--- springapp/src/main/java/mk/profesori/springapp/Model/Post.java	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ springapp/src/main/java/mk/profesori/springapp/Model/Post.java	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -20,5 +20,5 @@
 
 import com.fasterxml.jackson.annotation.JsonIdentityInfo;
-import com.fasterxml.jackson.annotation.ObjectIdGenerators;
+import com.voodoodyne.jackson.jsog.JSOGGenerator;
 
 import lombok.NoArgsConstructor;
@@ -27,5 +27,5 @@
 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
 @DiscriminatorColumn(name = "post_type", discriminatorType = DiscriminatorType.STRING)
-@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "postId")
+@JsonIdentityInfo(generator = JSOGGenerator.class)
 @NoArgsConstructor
 public class Post {
Index: springapp/src/main/java/mk/profesori/springapp/Model/_Thread.java
===================================================================
--- springapp/src/main/java/mk/profesori/springapp/Model/_Thread.java	(revision 3a44163af6d587748f82a3fedf08f1a492e83220)
+++ springapp/src/main/java/mk/profesori/springapp/Model/_Thread.java	(revision 2998dc401de4529373b17f60fbfea3c66b65dea0)
@@ -27,5 +27,5 @@
     private Subject targetSubject;
 
-    // TODO
+    // TODO threadovi
     /*
      * public _Thread(String title, String content, List<String> tags, Section
