Visit the app at myreviews.my
Or read the instructions below to host your own.
I have a need for this app as I visit and order from many places and want to keep track of my personal reviews on them, as I kept ordering from the same bad places that look good on paper.
At some point, Google Keep becomes unmanageable, and it's also not searchable. GSheets would be better, but an app is best.
I mainly chose this stack as I want to learn them. They are not used in my daily job.
Backend:
- Golang with standard library only (no framework): I will repeat. No framework by default.
- slogs for logging. lumberjack for log file rotation.
- Sever-Send Events to tail the log file
- No ORM. Use raw SQLs and sqlc for typed queries: This is the best db experience I have ecome across.
- Goose to manage migrations: It's alright.
- Elasticsearch: Bad experience with the Typed API. Let's just use the Untyped API.
- Example: The bulk operations just don't work with the Typed API.
Frontend:
- React and Typescript
- Vite for building
- Zustand for state management: I like it
- Mantine UI: quite good, can use again
- Tailwind: I do get some conflicts with Mantine as Mantine is not Tailwind-native, but no major blocker
Backend:
- Start postgres server
- Start elasticsearch server
- On WSL:
- https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html
curl -fsSL https://elastic.co/start-local | sh- Next time, use
docker compose upin the elasticsearch folder, aftersudo dockerd - Verify with
docker ps - Verify again by visiting localhost:9200
- Kibana: localhost:5601
- On Native Arch:
sudo pacman -S elasticsearchsudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive- Use the password in
.envrc sudo systemctl enable elasticsearchsudo systemctl start elasticsearch- Verify by visiting localhost:9200
- On WSL:
cd serverdirenv allow .createdb myreviewsgoose upair
Frontend:
cd webdirenv allow .npm run devornpx vite
- Write the SQL in
query.sql sqlc generate: The code is added tomodels/
make build-bemake build-fe
- I wasn't able to a inject a more extensive use of channels and concurrency patterns: Channels were used, but quite limitedly.
- sqlc is great and I want to use it again, but I can't figure out a way to force it to always use int. At first, I
tried to live with int32, but I hated the fact that I have to remember something is int32 or intt. In the end, I forced
everything to int, but even with the current config, it will generate Postgres's
integer[]asint32[]and I had to manually make the change aftersqlc generate. This may be improved in a future version. - I wasn't sure at first whether the i18n of backend error messages should be done on the backend or on the frontend,
but by now I have a preference: doing it all on the frontend will allow the frontend to check the error message more
easily (e.g.
if (error?.message?.toLowerCase()?.includes("access denied")). However, the tradeoff goes the other way if there are multiple frontends.