{"id":18390668,"url":"https://github.com/naren-jha/inbox-app","last_synced_at":"2026-05-05T22:43:52.925Z","repository":{"id":169491388,"uuid":"562635019","full_name":"naren-jha/inbox-app","owner":"naren-jha","description":"Cassandra demo app - An email application where millions of users can send emails/messages to one another","archived":false,"fork":false,"pushed_at":"2024-03-02T22:23:29.000Z","size":115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-12T07:58:46.589Z","etag":null,"topics":["cassandra","cassandra-cql","github-login","spring-boot"],"latest_commit_sha":null,"homepage":"","language":"Java","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/naren-jha.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-06T23:20:00.000Z","updated_at":"2023-10-05T05:32:17.000Z","dependencies_parsed_at":"2024-03-02T23:26:50.185Z","dependency_job_id":"87af6155-5465-4103-9b55-963bffb33c06","html_url":"https://github.com/naren-jha/inbox-app","commit_stats":null,"previous_names":["naren-jha/inbox-app"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naren-jha%2Finbox-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naren-jha%2Finbox-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naren-jha%2Finbox-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/naren-jha%2Finbox-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/naren-jha","download_url":"https://codeload.github.com/naren-jha/inbox-app/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248537101,"owners_count":21120701,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["cassandra","cassandra-cql","github-login","spring-boot"],"created_at":"2024-11-06T01:48:46.180Z","updated_at":"2026-05-05T22:43:47.899Z","avatar_url":"https://github.com/naren-jha.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# inbox-app\n\n## Cassandra Docs\n* https://cassandra.apache.org/doc/latest/\n* https://cassandra.apache.org/doc/latest/cassandra/architecture/index.html\n\n--\n\n* https://cassandra.apache.org/doc/latest/cassandra/data_modeling/index.html\n* https://www.datastax.com/blog/basic-rules-cassandra-data-modeling\n* You can also use List, Set, Map as columns in Cassandra: https://www.datastax.com/blog/coming-12-collections-support-cql3\n* https://www.datastax.com/blog/cql-improvements-cassandra-21\n* https://www.datastax.com/blog/whats-new-cassandra-21-better-implementation-counters\n* https://www.datastax.com/blog/lightweight-transactions-cassandra-20\n* https://www.datastax.com/examples\n* https://www.datastax.com/examples/astra-netflix\n* https://www.datastax.com/examples/astra-tik-tok\n* https://youtu.be/fcohNYJ1FAI\n* https://youtu.be/u6pKIrfJgkU\n* https://academy.datastax.com/#/courses/c5b626ca-d619-45b3-adf2-a7d2b940a7ee\n* https://www.youtube.com/playlist?list=PLqq-6Pq4lTTYzKjjA1C_jbic95tmq9FQt\n* https://docs.datastax.com/en/archived/cql/3.1/cql/cql_using/use_counter_t.html\n* https://www.datastax.com/blog/putting-some-structure-storage-engine\n\n\n## App Design Doc:\n* https://drive.google.com/file/d/1RneJhMHor6yS3b2wnxkg-5wLwpyPf39t/view?usp=sharing\n\n\n## End result\nAfter User SignUp:\n\u003cimg width=\"1788\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202012282-75d79f4d-5199-4678-919e-124458fcb4fc.png\"\u003e\n\nEmpty folder (no sent items yet):\n\u003cimg width=\"1792\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202012450-ee8c3532-a59f-4982-9d33-d987fa83a0f9.png\"\u003e\n\n\nEmail View:\n\u003cimg width=\"1787\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202012577-4d573907-f865-45dc-841a-483c97214bc4.png\"\u003e\n\nComposing a new email:\n\u003cimg width=\"1790\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202032480-64263e6b-1ca5-4ca3-ba18-1432fb254a75.png\"\u003e\n\nA new email lands in all receiving user's inbox:\n\u003cimg width=\"1790\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202032609-5129a94b-6e25-4d69-9b2c-6a09b307fe85.png\"\u003e\n\nAnd is also kept in sent items of sender user:\n\u003cimg width=\"1792\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202032833-ca2ab271-6774-4d48-b248-1335993ccc92.png\"\u003e\n\nEmail view:\n\u003cimg width=\"1782\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202033017-9e57b72b-5258-4c2f-a9bf-8b2e8fd6e14e.png\"\u003e\n\n## Cassandra data model so far:\n* These are the two high-level goals for data modeling in Cassandra:\n  1. Spread data evenly around the cluster\n  2. Minimize the number of partitions you read from\n  \nLets see what all tables are created. If we `describe main` cluster, we can see all the table schema.\n\n```\ntoken@cqlsh\u003e use main;\ntoken@cqlsh:main\u003e describe main;\n\nCREATE KEYSPACE main WITH replication = {'class': 'NetworkTopologyStrategy', 'asia-south1': '3'}  AND durable_writes = true;\n\nCREATE TABLE main.folders_by_user (\n    user_id text,\n    created_at_uuid uuid,\n    label text,\n    color text,\n    PRIMARY KEY (user_id, created_at_uuid, label)\n) WITH CLUSTERING ORDER BY (created_at_uuid ASC, label ASC)\n    AND additional_write_policy = '99PERCENTILE'\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}\n    AND comment = ''\n    AND compaction = {'class': 'org.apache.cassandra.db.compaction.UnifiedCompactionStrategy'}\n    AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}\n    AND crc_check_chance = 1.0\n    AND default_time_to_live = 0\n    AND gc_grace_seconds = 864000\n    AND max_index_interval = 2048\n    AND memtable_flush_period_in_ms = 0\n    AND min_index_interval = 128\n    AND read_repair = 'BLOCKING'\n    AND speculative_retry = '99PERCENTILE';\n\nCREATE TABLE main.messages_by_id (\n    id uuid PRIMARY KEY,\n    body text,\n    \"from\" text,\n    subject text,\n    \"to\" list\u003ctext\u003e\n) WITH additional_write_policy = '99PERCENTILE'\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}\n    AND comment = ''\n    AND compaction = {'class': 'org.apache.cassandra.db.compaction.UnifiedCompactionStrategy'}\n    AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}\n    AND crc_check_chance = 1.0\n    AND default_time_to_live = 0\n    AND gc_grace_seconds = 864000\n    AND max_index_interval = 2048\n    AND memtable_flush_period_in_ms = 0\n    AND min_index_interval = 128\n    AND read_repair = 'BLOCKING'\n    AND speculative_retry = '99PERCENTILE';\n\nCREATE TABLE main.messages_by_user_folder (\n    user_id text,\n    label text,\n    created_at_uuid uuid,\n    \"from\" text,\n    subject text,\n    unread boolean,\n    PRIMARY KEY ((user_id, label), created_at_uuid)\n) WITH CLUSTERING ORDER BY (created_at_uuid DESC)\n    AND additional_write_policy = '99PERCENTILE'\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}\n    AND comment = ''\n    AND compaction = {'class': 'org.apache.cassandra.db.compaction.UnifiedCompactionStrategy'}\n    AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}\n    AND crc_check_chance = 1.0\n    AND default_time_to_live = 0\n    AND gc_grace_seconds = 864000\n    AND max_index_interval = 2048\n    AND memtable_flush_period_in_ms = 0\n    AND min_index_interval = 128\n    AND read_repair = 'BLOCKING'\n    AND speculative_retry = '99PERCENTILE';\n```\n\n## data in tables and end result:\n### folders_by_user\n\u003cimg width=\"1093\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202035827-68643202-a717-48ab-b6cc-fd8bdab5d894.png\"\u003e\n\n### messages_by_id\n\u003cimg width=\"1722\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202036042-ba4d3417-60e2-4950-9443-31d266ad8e4a.png\"\u003e\n\n### messages_by_user_folder\n\u003cimg width=\"1122\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202036155-743f6b84-c30b-467f-8950-e30713e3fc15.png\"\u003e\n\nSending email to multiple users at a time\n\u003cimg width=\"1792\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202037549-d6952d31-e2a6-4ed7-92df-1a4b0dba5d7f.png\"\u003e\n\nNew email received:\n\u003cimg width=\"1792\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202037681-e97733f3-6240-47e5-a05e-27f953e2cf84.png\"\u003e\n\n\u003cimg width=\"1786\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202037763-67caab2b-1815-4f27-96ec-4628697bd3a1.png\"\u003e\n\nDB console after this new message:\n\u003cimg width=\"1743\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/202038081-ef7ffece-e9ce-49d9-bf98-0d38d9493273.png\"\u003e\n\n### Folder wise unread counter\n- counter tables in Cassandra has to be a dedicated table.\n- i.e., columns in a counter table can be either primarykey (partitioning key or clustering key) column, or counter column itself\n- that means, you cannot have non-priparykey, non-counter column in a counter table.\n- you can run increment/decrement queries on counter columns of a counter table, like - \n`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.\n\nmaintaining unread email counter per folder\n\u003cimg width=\"1791\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/203164105-01ed1960-aa47-443f-91f0-c61f292cc035.png\"\u003e\n\nmarking message read/unread:\n\u003cimg width=\"1791\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/203164417-44b5a4ba-3d42-4c16-85b0-740dfdb75c22.png\"\u003e\n\ntable data:\n\u003cimg width=\"1352\" alt=\"image\" src=\"https://user-images.githubusercontent.com/58611230/203164496-d1d101bf-bd1a-49f7-80d9-49d1ef7f3c0d.png\"\u003e\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnaren-jha%2Finbox-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnaren-jha%2Finbox-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnaren-jha%2Finbox-app/lists"}