{"id":17997366,"url":"https://github.com/danielhe4rt/event-ticket-system-rs","last_synced_at":"2025-06-16T03:38:00.124Z","repository":{"id":249797461,"uuid":"832560258","full_name":"danielhe4rt/event-ticket-system-rs","owner":"danielhe4rt","description":"Yet another Rust PoC but now for events!","archived":false,"fork":false,"pushed_at":"2024-07-23T14:01:33.000Z","size":26,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-13T07:57:36.944Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/danielhe4rt.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":"2024-07-23T09:13:32.000Z","updated_at":"2024-08-30T13:15:55.000Z","dependencies_parsed_at":"2024-10-29T21:46:07.034Z","dependency_job_id":null,"html_url":"https://github.com/danielhe4rt/event-ticket-system-rs","commit_stats":null,"previous_names":["danielhe4rt/event-ticket-system-rs"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/danielhe4rt/event-ticket-system-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhe4rt%2Fevent-ticket-system-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhe4rt%2Fevent-ticket-system-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhe4rt%2Fevent-ticket-system-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhe4rt%2Fevent-ticket-system-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danielhe4rt","download_url":"https://codeload.github.com/danielhe4rt/event-ticket-system-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danielhe4rt%2Fevent-ticket-system-rs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260090728,"owners_count":22957263,"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":[],"created_at":"2024-10-29T21:18:09.391Z","updated_at":"2025-06-16T03:38:00.103Z","avatar_url":"https://github.com/danielhe4rt.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Event Ticket System\n\nA heavy read application demo using monstrously awesome events as our payload!\n\n## Core Concept\n\nIn this project, we're working with the idea of creating all the rows related to seats in a specific venue before sending it to the public. So, if the venue that your event will take place has 50k seats, you be creating 50k tickets.\n\nAlso, to avoid race condition for the ones that will be buying the tickets, we're gonna be using CDC (Change Data Capture) to make sure that when someone start the checkout process, no one will be able to purchase that specific seat/ticket.\n\nImagine that you have 15 minutes to finish the purchase. When you start it, a row with your `session_id, event_id and ticket_id` will be inserted at `order_queue` table which has:\n\n```cql\nCREATE TABLE order_queue (\n\tevent_id uuid,\n\tticket_id uuid,\n\tstarted_at timestamp,\n\tsession_id text,\n\tPRIMARY (event_id, ticket_id, started_at)\n) WITH cdc = {'enabled': 'true'} AND default_time_to_live = 60 * 15\n```\n\nIf someone starts to purchase and stop in the middle of it, we can track them because for every operation related to the `order_queue`, a new log gonna be created\n\n```text\ncqlsh:ks\u003e select * from order_queue_scylla_cdc_log  LIMIT 1;\n\ncdc$stream_id                      | cdc$time                             | cdc$batch_seq_no | cdc$deleted_session_id | cdc$end_of_batch | cdc$operation | cdc$ttl | event_id                             | session_id                           | started_at                      | ticket_id\n------------------------------------+--------------------------------------+------------------+------------------------+------------------+---------------+---------+--------------------------------------+--------------------------------------+---------------------------------+--------------------------------------\n 0x8a78ebc0e79835301f196f14180001f1 | d907b072-48d1-11ef-5dc7-708fddfabcab |                0 |                   null |             True |             2 |       5 | a00924e9-0009-4563-90b7-a294d5812ada | 2eff47b7-7877-4189-bc57-281e529d9bc8 | 2024-07-23 08:59:19.829000+0000 | 69acda0c-be3f-435b-8adf-6b723a08d4f4\n\n```\n\nUsing the crate [scylla-cdc-rust](https://github.com/scylladb/scylla-cdc-rust/) it gives us a way better DX for using this feature:\n\n```rust\nimpl Consumer for OrderQueueConsumer {  \n    async fn consume_cdc(\u0026mut self, mut data: CDCRow\u003c'_\u003e) -\u003e anyhow::Result\u003c()\u003e {  \n        println!(\"Stream ID: {:}\", data.stream_id);\n        println!(\"TTL: {:}\", data.ttl);\n\n\t\tlet ticket_id = data.take_value(\"ticket_id\").unwrap().as_uuid().unwrap();\n\t}\n}\n```\n\n### Tables\n\n* **venue_sections:** stores information about the event venue, pricing per seat and amount of seats from a specific section\n* **events:** information about the events happening around\n* **available_events [mv]:** retrieves only events that still have tickets to sell\n* **tickets**: holds all the tickets which is created after a new event set up.\n* **available_tickets [mv]:** retrieves only tickets with status 'available'\n* **orders:** stores user attempts of purchase\n* **order_queue:** stores the user and session with time limit for the purchase being accomplished.\n* **order_queue_scylla_cdc_log:** receives all changes on order_queue (observer table).\n\n\n### Data Modeling\n\n```cql\nCREATE KEYSPACE ks WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': '3'}  AND durable_writes = true;\n\nCREATE TABLE ks.tickets (\n    event_id uuid,\n    ticket_id uuid,\n    price decimal,\n    section uuid,\n    status text,\n    type_id text,\n    PRIMARY KEY (event_id, ticket_id)\n) WITH CLUSTERING ORDER BY (ticket_id ASC)\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'}\n    AND comment = ''\n    AND compaction = {'class': 'SizeTieredCompactionStrategy'}\n    AND compression = {'sstable_compression': '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 speculative_retry = '99.0PERCENTILE';\n\nCREATE MATERIALIZED VIEW ks.available_tickets AS\n    SELECT event_id, status, ticket_id, price, section, type_id\n    FROM ks.tickets\n    WHERE event_id IS NOT null AND status IS NOT null AND ticket_id IS NOT null\n    PRIMARY KEY ((event_id, status), ticket_id)\n    WITH CLUSTERING ORDER BY (ticket_id ASC)\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'}\n    AND comment = ''\n    AND compaction = {'class': 'SizeTieredCompactionStrategy'}\n    AND compression = {'sstable_compression': '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 speculative_retry = '99.0PERCENTILE';\n\nCREATE TABLE ks.order_queue (\n    event_id uuid,\n    ticket_id uuid,\n    started_at timestamp,\n    session_id text,\n    PRIMARY KEY (event_id, ticket_id, started_at)\n) WITH CLUSTERING ORDER BY (ticket_id ASC, started_at ASC)\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'}\n    AND comment = ''\n    AND compaction = {'class': 'SizeTieredCompactionStrategy'}\n    AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}\n    AND crc_check_chance = 1.0\n    AND default_time_to_live = 5\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 speculative_retry = '99.0PERCENTILE';\n\nCREATE TABLE ks.venue_sections (\n    venue_id uuid,\n    section_id uuid,\n    type_id text,\n    price decimal,\n    seats_count int,\n    PRIMARY KEY (venue_id, section_id, type_id)\n) WITH CLUSTERING ORDER BY (section_id ASC, type_id ASC)\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'}\n    AND comment = ''\n    AND compaction = {'class': 'SizeTieredCompactionStrategy'}\n    AND compression = {'sstable_compression': '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 speculative_retry = '99.0PERCENTILE';\n\nCREATE TABLE ks.orders (\n    order_id uuid PRIMARY KEY,\n    event_id uuid,\n    purchased_at timestamp,\n    status text,\n    total_price decimal,\n    user_id uuid\n) WITH bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'}\n    AND comment = ''\n    AND compaction = {'class': 'SizeTieredCompactionStrategy'}\n    AND compression = {'sstable_compression': '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 speculative_retry = '99.0PERCENTILE';\n\nCREATE TABLE ks.order_queue_scylla_cdc_log (\n    \"cdc$stream_id\" blob,\n    \"cdc$time\" timeuuid,\n    \"cdc$batch_seq_no\" int,\n    \"cdc$deleted_session_id\" boolean,\n    \"cdc$end_of_batch\" boolean,\n    \"cdc$operation\" tinyint,\n    \"cdc$ttl\" bigint,\n    event_id uuid,\n    session_id text,\n    started_at timestamp,\n    ticket_id uuid,\n    PRIMARY KEY (\"cdc$stream_id\", \"cdc$time\", \"cdc$batch_seq_no\")\n) WITH CLUSTERING ORDER BY (\"cdc$time\" ASC, \"cdc$batch_seq_no\" ASC)\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'enabled': 'false', 'keys': 'NONE', 'rows_per_partition': 'NONE'}\n    AND comment = 'CDC log for ks.order_queue'\n    AND compaction = {'class': 'TimeWindowCompactionStrategy', 'compaction_window_size': '60', 'compaction_window_unit': 'MINUTES', 'expired_sstable_check_frequency_seconds': '1800'}\n    AND compression = {'sstable_compression': '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 = 0\n    AND max_index_interval = 2048\n    AND memtable_flush_period_in_ms = 0\n    AND min_index_interval = 128\n    AND speculative_retry = '99.0PERCENTILE';\n\nCREATE TABLE ks.events (\n    event_id uuid PRIMARY KEY,\n    date timestamp,\n    event_type text,\n    has_tickets boolean,\n    name text,\n    slug text,\n    venue_id uuid\n) WITH bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'}\n    AND comment = ''\n    AND compaction = {'class': 'SizeTieredCompactionStrategy'}\n    AND compression = {'sstable_compression': '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 speculative_retry = '99.0PERCENTILE';\n\nCREATE MATERIALIZED VIEW ks.available_events AS\n    SELECT has_tickets, event_id, date, event_type, name, slug, venue_id\n    FROM ks.events\n    WHERE has_tickets IS NOT null AND event_id IS NOT null\n    PRIMARY KEY (has_tickets, event_id)\n    WITH CLUSTERING ORDER BY (event_id ASC)\n    AND bloom_filter_fp_chance = 0.01\n    AND caching = {'keys': 'ALL', 'rows_per_partition': 'ALL'}\n    AND comment = ''\n    AND compaction = {'class': 'SizeTieredCompactionStrategy'}\n    AND compression = {'sstable_compression': '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 speculative_retry = '99.0PERCENTILE';\n```\n\n### INSERT Queries\n\n#### 1. Insert into `tickets`\n```sql\nINSERT INTO tickets (event_id, ticket_id, price, section, status, type_id) VALUES (?, ?, ?, ?, ?, ?);\n```\n\n#### 2. Insert into `order_queue`\n```sql\nINSERT INTO order_queue (event_id, ticket_id, started_at, session_id) VALUES (?, ?, ?, ?);\n```\n\n#### 3. Insert into `venue_sections`\n```sql\nINSERT INTO venue_sections (venue_id, section_id, type_id, price, seats_count) VALUES (?, ?, ?, ?, ?);\n```\n\n#### 4. Insert into `orders`\n```sql\nINSERT INTO orders (order_id, event_id, purchased_at, status, total_price, user_id) VALUES (?, ?, ?, ?, ?, ?);\n```\n\n\n#### 5. Insert into `events`\n```sql\nINSERT INTO events (event_id, date, event_type, has_tickets, name, slug, venue_id) VALUES (?, ?, ?, ?, ?, ?, ?);\n```\n\n### SELECT Queries\n\n#### 1. Select from `tickets`\n```sql\nSELECT event_id, status, ticket_id, price, section, type_id FROM tickets WHERE event_id = ? AND status IS NOT null AND ticket_id IS NOT null;\n```\n\n#### 2. Select from `order_queue`\n```sql\nSELECT event_id, ticket_id, started_at, session_id FROM order_queue WHERE event_id = ? AND ticket_id = ? AND started_at = ?;\n```\n\n#### 3. Select from `venue_sections`\n```sql\nSELECT * FROM venue_sections WHERE venue_id = ? AND section_id = ? AND type_id = ?;\n```\n\n#### 4. Select from `orders`\n```sql\nSELECT * FROM orders WHERE order_id = ?;\n```\n\n#### 5. Select from `events`\n```sql\nSELECT * FROM events WHERE event_id IS NOT null AND has_tickets IS NOT null;\n```\n\n#### 6. Select from `available_tickets`\n```sql\nSELECT * FROM available_tickets WHERE event_id IS NOT null AND status IS NOT null AND ticket_id IS NOT null;\n```\n\n#### 7. Select from `available_events`\n```sql\nSELECT * FROM available_events WHERE has_tickets = true AND event_id IS NOT null;\n```\n\nThese are the possible `INSERT` and `SELECT` queries based on the provided schema.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielhe4rt%2Fevent-ticket-system-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanielhe4rt%2Fevent-ticket-system-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanielhe4rt%2Fevent-ticket-system-rs/lists"}