{"id":37187334,"url":"https://github.com/eneskzlcn/softdare","last_synced_at":"2026-01-14T21:46:22.795Z","repository":{"id":59040403,"uuid":"533462001","full_name":"eneskzlcn/softdare","owner":"eneskzlcn","description":"A social media web application allows user to follow other users, publish new posts,  comment on published posts, like posts or comments. Users also has their timelines according to the followed users, trend page that shows the trend posts, search operation to find another users, get mailed on account creation or notifications.","archived":false,"fork":false,"pushed_at":"2022-09-22T14:53:32.000Z","size":64964,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-06-21T13:00:53.704Z","etag":null,"topics":["adapter-pattern","golang","gotemplate-engine","mailing-services","mux-router","nlayer-architecture","notification-service","rabbitmq","session-management","social-media","web-application","web-development"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eneskzlcn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-09-06T18:52:28.000Z","updated_at":"2024-06-21T13:00:53.704Z","dependencies_parsed_at":"2023-01-18T19:15:45.463Z","dependency_job_id":null,"html_url":"https://github.com/eneskzlcn/softdare","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eneskzlcn/softdare","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneskzlcn%2Fsoftdare","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneskzlcn%2Fsoftdare/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneskzlcn%2Fsoftdare/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneskzlcn%2Fsoftdare/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eneskzlcn","download_url":"https://codeload.github.com/eneskzlcn/softdare/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eneskzlcn%2Fsoftdare/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28436193,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T21:32:52.117Z","status":"ssl_error","status_checked_at":"2026-01-14T21:32:33.442Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adapter-pattern","golang","gotemplate-engine","mailing-services","mux-router","nlayer-architecture","notification-service","rabbitmq","session-management","social-media","web-application","web-development"],"created_at":"2026-01-14T21:46:22.167Z","updated_at":"2026-01-14T21:46:22.791Z","avatar_url":"https://github.com/eneskzlcn.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"### About Project\n\nThis is a social media project that users can post their\nwritings, follow other users, comment on other users posts,\nlike other users posts or comments.\n\nThe screenshots of the project can be found:\n\n[Home Page](https://eneskzlcn.github.io/my-published-images/softdare/home.png)\n\n[Login](https://eneskzlcn.github.io/my-published-images/softdare/login.png)\n\n[User Profile](https://eneskzlcn.github.io/my-published-images/softdare/another-users-profile.png)\n\n[Post Details](https://eneskzlcn.github.io/my-published-images/softdare/post-comment.png)\n\n[Trends](https://eneskzlcn.github.io/my-published-images/softdare/trends.png)\n\n### Local Setup To Run\n\nYou need the docker installed on your machine to run the\napplication.\n\n- `docker compose up -d` to start rabbitmq and postgres database services.\n- `go mod tidy` to install all needed dependencies and a cleanup for not needed ones...\n- `make migrate-tables` to create needed tables on postgres database\n- `make build` to build the application and `make run` to start.\nor you can directly use `make start` to build first then run.\n\n### Additional Information About Local Setup\n- You can find all the database schema under postgres/migration/schema.sql. If you\nwant to contribute or use for your own purposes, you can simply add the tables you\nwant to create to schema.sql and the command `make migrate-tables` will rebuild \nall the tables for you after you clean up the database with the command `make drop-tables`\n(the thing you need to remember, you should add your new table to postgres/migration/drop.sql\ntoo to clean up correctly for next `make drop-tables` commands.).\n\n- If you want to clean up all the tables in database and restart again you can\n  call `make drop-tables` to clean up the database , and `make migrate-tables` to create\n  the tables again.\n\n- If you want to consume one more queue from rabbitmq, you need to add the queue name to\nthe config files which is under the .dev/ folder. After you add that queue name to the config\nfile, the program will create the queue automatically when it restarts.\n\n- If you want to add one more consumer for a queue, you can find the consumers under\ninternal/client/queue. You can add a consumer function like the others I write and provide\na consume operation for your purposes.\n\n- You should not change the directory of gohtml templates. Because there is\nan `embed` usage to read that template which should exactly be in the directory that\nembed expects(or you should change the directory that embed reads from internal/web/template.go too.)\n\n- If you want to add a new page(new .gohtml) you should put it to the internal/web/templates if it\nis not a reusable or layout component(that ones go to the include/ directory under the templates directory.) and then\nyou should name your template by registering it to the map sits on internal/web/handler.go (in the init function of Handler struct)\n\n- If you want to add a new feature starting from web handler and goes to the repository then you should register your\nweb handler functions to the Handler struct defined under internal/web/ directory and better to\nkeep in different file(you can look at my examples like profile, post ,home or etc.), and register\nservice functions to the Service struct in the internal/service and better to\nkeep different file, and register your data access layer functions to\nRepository struct in the internal/repository and better to keep in different file. Do not forget to register your web handler\nto the Handler by adding your handler with its route and method to the RegisterHandlers function\nof the Handler struct which is in internal/web/handler.go\n\n### Local Setup For Tests\n- `go mod tidy` to install all needed dependencies and a cleanup for not needed ones...\n- `make clean` to clear all additional files.\n- `make generate-mocks` to generate all needed mock to run tests.\n- `make test` to run all written tests.\n\n### Architectural Decisions\nThis project teach me a lot of on how you need to choose\nan architecture for your application. I was generally using DDD approach\nto create backend applications which recommends that you need to\nkeep inside the things that domain consist of. An example\nif you are creating an order domain, then all structures, functionalities,\ntests, business and database access operations should be in the package of that domain.\n\nSo first, I tried to make all the domains like post, login, comment, user etc.\nseperated and independent of each other. After I structured the project like \nthat, I enjoyed and thought to gain a victory about that. Then when time comes\nto the creating new features on that architecture things started to get more complicated.\nEvery need were causing a dependency between domains/subdomains. The most great\nexample was the entities. I thought any way to protect that structure\nso I see that it will be costly. So I decided to move all the entities out of\nthe domains and all the domains can reach them without creating a dependency\nbetween domains. The folder structure were like;\n\n- entities/\n- login/\n- post/\n\nAfter this change, I was comfortable to reach the entities from anywhere\nand it was easy to add or remove an entity for new feature purposes.\n\nWorking on new things obligate me to repeat the implementation of same functions\njust to keep the domains independent. An example of that is a data access or business\nfunction one domain has is also used by another domain. But you can not pass directly\nto maintain independence.\n\nI googled about that and see the architecture generally used by Java\nor C# backend programmers named `n-Layered Architecture`. I realised that\nthe architecture I need to use in a monolithic web application should\nbe that. Because there is no domain specific abstractions so that\nyou can make a folder/package structure like;\n```\n   - entity/\n   - services/\n   - repository/\n   - api/\n   - web/\n   - mobile/\n   ...\n```\nAt last, I chose that architecture as a project architecture and everything\nbecome more comfortable, flexible and easier.\n\nAs a result, I tried to feel like a startup company that must keep things faster\nto deploy their app. Generally they prefer monolithic way to deploy the first\nrelease as much as faster and then seperated the system to the little services when needed( microservices ).\nSo I think that making all the domains seperated even doing a monolithic application effect the process \nafter first release, so it will be easier to decouple the services as independent microservices.\nBut I learned that making a monolithic application in that\nway is very hard and painful.\n\n### Caching\nI use the caching to cache trends data which always going to be same for a while.\nNormally, trends can change anytime. But, keeping the trends in cache for a while\nlike 1 minutes, will not affect the correctness too much instead it will provide\nfaster results for any user want to see the trends.\n\n### Configs\nYou can find the configuration filed under .dev/ folder for any environment(I have not\na production environment yet). After the application starts LoadConfig functions\nin the internal/config package reads related yaml configs from .dev/ and all configuration\nvariables become a structured data that you pass in any related service that needs an extra\nconfiguration properties.\n\n### Secrets\nSecrets are the same with configs but the things I need to keep private. An\nexample of that is mail service configuration properties which needs my email\nand its password to send an email.\n\n### Mail Service\nMail service sends mail to the users when you needed. When you look at the mail\nservice you notice that it takes all the configuration properties like username,\nhost, port and password from configs (which is a secret config). For security,\nI kept that configurations as secret and do not push it to my remote repository.\nIf you want to configure it with your own credentials you have two different way you can \nfollow. In first way, which you do not need to touch any path specification for your\nsecrets, you can simply create a file named secrets.yaml to directory named .secrets\nwhich lives in project directory ($project_directory/.secrets/secrets.yaml).\nThen the other parts going to get handled by current code. In the second way, you\ncan place your secrets anywhere you want on one condition that you need to change\nthe path and file name with yours in LoadConfig[config.Secret] functions from\ncmd/main.go\n\n### External Modules Used In Project\n- `html/templates` built-in module as a html parser and renderer technology.\n- `go.uber.org/zap` logger module to handle logging operations.\n- `go-ozzo/ozzo-validation` validation module to validate special structures and inputs.\n- `/rs/xid` xid module to generate xid for database entities.\n- `spf13/viper` configuration module to handle and structure environment specific configurations.\n- `golangcollege/sessions` session module to handle all session operations on the application.\n- `bluele/gcache` to cache user data to reduce database read load and provide faster\n- `bootstrap` to provide responsive ui components with nice styling with less css.\n- `fontawesome` to use custom icons that fontawesome provides.\nresponses.\n\n### Testing Modules\n- `DATA-DOG/go-sqlmock` sql db mock module to mock the database on\ntesting repository layer.\n- `golang/mock` as a mock module to mock the interfaces and test\nthe objects independently.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feneskzlcn%2Fsoftdare","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feneskzlcn%2Fsoftdare","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feneskzlcn%2Fsoftdare/lists"}