Assumptions:
-
Usernames are unique.
-
Data fetching pattern is described similar to popular apps, such as Whatsapp, FB Messenger, Telegram, etc... Where users once login can see a list of all messages sent to them or by them sorted by time in which they are sent in a DESC manner.
-
Messages history retrieval does not apply grouping by sender or receiver yet!
-
For logical & physical data modeling purposes, de-normalization of data schema is necessary to serve optimal performance & promote efficient retrieval. This leads to a bit of sacrifice when the need to write data could require batching sometimes.
Minimizing Batching/Atomic operations whenever possible to avoid impacting performance should be kept in mind though. -
Layer-first code organization approach as opposed to entity-first or feature-first for 2 reasons:
- Avoiding cyclic imports.
- Making it familiar & straightforward. However, yet some layers are ignored, again, for the sake of the demo and focusing on core functionality. One of such layers can be Repo to encapsulate data access logic,
-
Token-based authentication is the method employed for Auth. Since a client-server arch can provide auth in different methods/mechanisms, this is the best fit here to avoid implications of other ways. Such other ways, can be listed as follows:
- Password-Based: Where users are required to send credentials each time they access a protected resource. That's not efficient in our case.
- MFA: Not suitable for the sake of this demo. As it adds extra layers that could lead to requiring more than just a password.
- OAuth: We need to stay basic, not fancy.
- Stateful Authentication: Why keep our server busy managing sessions and analyzing cookies while we can stay stateless, can't we?!
Thus JWT is picked up for easy interaction & smooth communication between the two parties (client & server) with pre-embedded credentials came from first auth operation as a handshake. Token expiration after one day would make sense to mitigate hacks, yet provide usage convenience.
Note: Important to understand that adopting HTTPS is the most important way to protect sniffing tokens over the network as it encrypts the data transmitted between the client & server or among services. Get rid of men in the middle in production settings.
Disclaimers:
-
Since this is a development assignment meant for exploration & situation assessment. No database users/roles are created for the sake of the app usage & connection. Default credentials are used. Set your own for security measures and best practices.
-
No data seeding!
-
Other environment parameters can be set & used across the app for more robust experience. Such as
DEBUG
&APP_ENV
flags e.g -
Logging is subject for enhancement.
-
Lack of Integration-Testing/E2E tests to verify API functionality. Due to tight deadline in a holiday season.
-
Simple input validation is conducted for the purpose of the demo. Rigorous validation with nicer error handling can be something to consider.
-
No Rate Limiting.
-
Auth is disabled for monitoring tools. Since it's meant for local dev experimentation. Though, it's still safer to activate even on local.
- Docker
- Docker Compose
-
Clone the repository.
-
Set the Environment Variables. Find the file named
.env.example
in the root directory of the project. Duplicate the file in the same path/location, rename the new one.env
then set the values of the environment variables listed within the file according to your environment respectively.
Well, you may wanna keepCASSANDRA_NODES
&&AUTH_HEADER_PREFIX
vars as-is with current values if you do wanna use the provideddocker-compose.yaml
file andPOSTMAN
collection & env without creating your own!Now you should be good to go.
Unless you'd like to play a bit with
.air.toml
configurations. Consult the Air's documentation for more details/instructions in this regard. -
Build:
$ docker compose up --build -d
-
Ensure all services are up & healthy first.
-
Migrate the DataStore:
Install golang-migrate/migrate CLI package to use.
Better with instructions for the respective OS you have as opposed to the "With Go toolchain" instructions on that page.
Additionally, Docker usage can be a breeze!Run the following command in CLI pointing to the project root. So, you can get your database schema created:
migrate -path internal/cassandra/migrations -database cassandra://cassandra:cassandra@localhost:9042/chat up
In case you encounter a db dirty state, just connect to Cassandra via any client to drop/remove all tables including theschema_migrations
table under thechat
keyspace. Or be a good citizen and force to the correct version instead. Then re-apply the migration direction desired!
I believe you know how to clear all db entries and drop the schema all at once:migrate -path internal/cassandra/migrations -database cassandra://cassandra:cassandra@localhost:9042/chat down
Visiting migrate's docs is both helpful & recommended as usual.
SQLTools vsCode extension by Matheus Teixeira is a good one for GUI experience.
DBeaver work bench is a good option too, but with PRO access for Apache Cassandra & Redis!
IMPORTANT NOTE: You want to Manually Invalidate Cache after some certain events including but not limited to the following list of events:
- Bringing DB down or dropping it.
- Migrating DB.
- Removal of DB Docker volumes.
-
Access the service at
http://localhost/api/v1/<path>
.
You can utilize the includedPOSTMAN
file with docs and environment setup to import at your end for convenience. "Find them at the root directory of the project injson
format"Remember to register & login to grab the
token
and set its value in the Auth headers of subsequent requests to protected endpoints. -
For Redis GUI client you can use Redis Insight as a good tool, works well on Linux/Ubuntu. Find yours as per your respective platform though!
Or get savvy & jump right into the CLI mystical world!!
Note: After connecting tolocalhost
default port, remember to set the db as1
instead of the defaultdb0
. 👇
- Visit
Grafana
on the configured addresshttp://localhost:3000/
via browser to stay on top of your game! - Choose a data-source from available ones (Prometheus, Loki) and play with it.
- You can create your own dashboards or even connect to cloud for Grafana's generous free-plan.
- You still can visit
Prometheus
without Grafana on its configured addresshttp://localhost:9090/
for raw metrics. - Few logs & events are logged on few levels, such as containers, but more are planned to be set soon.
First ensure Cassandra DB server is up & running on your localhost.
Or somewhere else but in this case you will need to adjust the tests cluster addresses manually in the code. Refer to internal/services/test_utils.go
for some constants like CLUSTER_ADDRS
.
You can use the IDE comfy testing tools. However, please make sure to adjust the IDE settings for Go: Test Timeout
to be set for something like 300s
which is equivalent to 5 minutes in such case. So, you allow it to take its time to establish a connection to cassandra DB and do all required jobs for test suites such as creating tables, seeding data, etc.
If you're on VSCode, adjusting timeout flag can be found as follows:
- File menu > Preferences > Settings. (Or hit CTRL + Comma keys on keyboard if you're on Linux)
- Search for
timeout
.
If you've Go extensionGo Team at Google
~v0.41.4
installed, then you should be able to locate that setting. - Find that one setting under Extensions > Go.
- Set the value to nearly 300 seconds or more. As Cassandra connection seems very expensive operation.
Visit the project-root directory from CLI and run:
$ go test ./... -v
For displaying of every single tiny log to stdout and stay on top of your game and be in control to check what went well and what goes wrong.
Note: Default timeout
is set to 10 minutes. This should be fine in our case.
Run:
$ go test ./...
For no verbosity. If you're only interested in finding what passed and what failed.
Set/Pass some flags like -timeout
to control tests timeout "defaults to 10 minutes". And -run
to only run a particular test.
Head to go help test
&& go help testflag
utilities docs for more detailed tips and hints on testing go modules. Good luck then!
POST /register
- Register a new userPOST /login
- Login a userPOST /send
- Send a messageGET /messages
- Retrieve message history
This is a free software distributed under the terms of the WTFPL
license along with MIT license as dual-licensed, You can choose whatever works for you.
Review the attached License
file within the source code for more details.
Here's a list of bunch of stuff to be done when time allows!
- Write integrations test cases to ensure tests cover user registration, login, message sending, and message retrieval.
Shout out!