https://github.com/naren-jha/inbox-app
Cassandra demo app - An email application where millions of users can send emails/messages to one another
https://github.com/naren-jha/inbox-app
cassandra cassandra-cql github-login spring-boot
Last synced: about 1 month ago
JSON representation
Cassandra demo app - An email application where millions of users can send emails/messages to one another
- Host: GitHub
- URL: https://github.com/naren-jha/inbox-app
- Owner: naren-jha
- Created: 2022-11-06T23:20:00.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2024-03-02T22:23:29.000Z (over 2 years ago)
- Last Synced: 2025-04-12T07:58:46.589Z (about 1 year ago)
- Topics: cassandra, cassandra-cql, github-login, spring-boot
- Language: Java
- Homepage:
- Size: 112 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# inbox-app
## Cassandra Docs
* https://cassandra.apache.org/doc/latest/
* https://cassandra.apache.org/doc/latest/cassandra/architecture/index.html
--
* https://cassandra.apache.org/doc/latest/cassandra/data_modeling/index.html
* https://www.datastax.com/blog/basic-rules-cassandra-data-modeling
* You can also use List, Set, Map as columns in Cassandra: https://www.datastax.com/blog/coming-12-collections-support-cql3
* https://www.datastax.com/blog/cql-improvements-cassandra-21
* https://www.datastax.com/blog/whats-new-cassandra-21-better-implementation-counters
* https://www.datastax.com/blog/lightweight-transactions-cassandra-20
* https://www.datastax.com/examples
* https://www.datastax.com/examples/astra-netflix
* https://www.datastax.com/examples/astra-tik-tok
* https://youtu.be/fcohNYJ1FAI
* https://youtu.be/u6pKIrfJgkU
* https://academy.datastax.com/#/courses/c5b626ca-d619-45b3-adf2-a7d2b940a7ee
* https://www.youtube.com/playlist?list=PLqq-6Pq4lTTYzKjjA1C_jbic95tmq9FQt
* https://docs.datastax.com/en/archived/cql/3.1/cql/cql_using/use_counter_t.html
* https://www.datastax.com/blog/putting-some-structure-storage-engine
## App Design Doc:
* https://drive.google.com/file/d/1RneJhMHor6yS3b2wnxkg-5wLwpyPf39t/view?usp=sharing
## End result
After User SignUp:

Empty folder (no sent items yet):

Email View:

Composing a new email:

A new email lands in all receiving user's inbox:

And is also kept in sent items of sender user:

Email view:

## Cassandra data model so far:
* These are the two high-level goals for data modeling in Cassandra:
1. Spread data evenly around the cluster
2. Minimize the number of partitions you read from
Lets see what all tables are created. If we `describe main` cluster, we can see all the table schema.
```
token@cqlsh> use main;
token@cqlsh:main> describe main;
CREATE KEYSPACE main WITH replication = {'class': 'NetworkTopologyStrategy', 'asia-south1': '3'} AND durable_writes = true;
CREATE TABLE main.folders_by_user (
user_id text,
created_at_uuid uuid,
label text,
color text,
PRIMARY KEY (user_id, created_at_uuid, label)
) WITH CLUSTERING ORDER BY (created_at_uuid ASC, label ASC)
AND additional_write_policy = '99PERCENTILE'
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.UnifiedCompactionStrategy'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair = 'BLOCKING'
AND speculative_retry = '99PERCENTILE';
CREATE TABLE main.messages_by_id (
id uuid PRIMARY KEY,
body text,
"from" text,
subject text,
"to" list
) WITH additional_write_policy = '99PERCENTILE'
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.UnifiedCompactionStrategy'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair = 'BLOCKING'
AND speculative_retry = '99PERCENTILE';
CREATE TABLE main.messages_by_user_folder (
user_id text,
label text,
created_at_uuid uuid,
"from" text,
subject text,
unread boolean,
PRIMARY KEY ((user_id, label), created_at_uuid)
) WITH CLUSTERING ORDER BY (created_at_uuid DESC)
AND additional_write_policy = '99PERCENTILE'
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.UnifiedCompactionStrategy'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair = 'BLOCKING'
AND speculative_retry = '99PERCENTILE';
```
## data in tables and end result:
### folders_by_user

### messages_by_id

### messages_by_user_folder

Sending email to multiple users at a time

New email received:


DB console after this new message:

### Folder wise unread counter
- counter tables in Cassandra has to be a dedicated table.
- i.e., columns in a counter table can be either primarykey (partitioning key or clustering key) column, or counter column itself
- that means, you cannot have non-priparykey, non-counter column in a counter table.
- you can run increment/decrement queries on counter columns of a counter table, like -
`update COUNTER_TABLE_NAME set COUNTER_COL_NAME = COUNTER_COL_NAME + 1 where SOME_OTHER_COL = SOME_VAL` note that here the record does not have to exist in advance with matching 'where clause'. If the record with the given where clause does not exist, cassandra will create a new entry with initial value for all counter columns as 0. So in this case if there is no entry for `SOME_OTHER_COL = SOME_VAL` when the query is executed, then cassandra will create a new entry and the value for `COUNTER_COL_NAME` for that entry will be updated from 0 to 1.
maintaining unread email counter per folder

marking message read/unread:

table data:
