Coding questions · OpenAI
Design Schema and Logic for Subscription Event Tracking
This question evaluates proficiency in event-driven data modeling, temporal state derivation, and implementation of SQL/Python logic to compute per-user subscription status and history within the Data Manipulation (SQL/Python) domain.
user_subscription_events
+----------+-------------+---------------------+-----------+---------+
| user_id | event_type | event_time | plan_type | source |
+----------+-------------+---------------------+-----------+---------+
| 101 | signup | 2023-05-01 09:03:12 | paid | web |
| 101 | cancel | 2023-06-10 14:27:45 | paid | web |
| 101 | signup | 2023-07-02 08:11:06 | paid | mobile |
| 202 | signup | 2023-05-05 11:55:20 | paid | email |
| 303 | cancel | 2023-05-07 16:02:09 | paid | support |
+----------+-------------+---------------------+-----------+---------+
Scenario
Subscription event pipeline feeding the experiment: users can signup, cancel, then signup again; downstream tables drive metrics and triggering code.
Question
Design the raw event table schema needed to derive a user's current subscription status and historical states. 2. Write SQL or Python logic that produces one row per user with their latest status, handling the edge case where a user signs up, cancels, and then signs up again. 3. Review the provided Python snippet that assigns variants and delivers the free-trial offer; identify at least three improvements or safeguards you would add.
Hints
Think append-only event logs, window functions, deduping by latest timestamp, idempotent triggers.
Design subscription events schema
Create SQL DDL for an append-only user_subscription_events table to capture subscription signups and cancels so downstream jobs can derive both current status and history. Enforce NOT NULL constraints and restrict event_type to 'signup' or 'cancel'. Add useful indexes for windowing by user and event_time using the provided columns. For this executable answer, return the sample rows that conform to the proposed schema, ordered by user_id and event_time.
Table user_subscription_events
| column | type | constraints |
|---|---|---|
| user_id | INTEGER | NOT NULL |
| event_type | VARCHAR(20) | NOT NULL, CHECK (event_type IN ('signup','cancel')) |
| event_time | TIMESTAMP | NOT NULL |
| plan_type | VARCHAR(20) | NOT NULL |
| source | VARCHAR(20) | NOT NULL |
Sample data:
| event_time | event_type | plan_type | source | user_id |
|---|---|---|---|---|
| 2023-05-01 09:03:12 | signup | paid | web | 101 |
| 2023-06-10 14:27:45 | cancel | paid | web | 101 |
| 2023-07-02 08:11:06 | signup | paid | mobile | 101 |
| 2023-05-05 11:55:20 | signup | paid | 202 | |
| 2023-05-07 16:02:09 | cancel | paid | support | 303 |
Expected output
A CREATE TABLE statement defining the raw event schema with constraints and supporting indexes. The table holds append-only rows for signups and cancels. Example rows consistent with the schema are shown.
| event_time | event_type | plan_type | source | user_id |
|---|---|---|---|---|
| 2023-05-01 09:03:12 | signup | paid | web | 101 |
| 2023-06-10 14:27:45 | cancel | paid | web | 101 |
| 2023-07-02 08:11:06 | signup | paid | mobile | 101 |
| 2023-05-05 11:55:20 | signup | paid | 202 | |
| 2023-05-07 16:02:09 | cancel | paid | support | 303 |
Hints
- Use a CHECK constraint to restrict event_type to allowed values.
- Index by (user_id, event_time) to speed up latest-event window functions.
- Append-only is typically enforced by ingestion process and auditing.
Latest Subscription Status Per User
Return one row per user from user_subscription_events with the user's most recent event details and derived current_status. Use active when the latest event is signup and canceled when it is cancel. If a user has multiple events at the same timestamp, prefer signup over cancel, then use source alphabetically as a deterministic final tie-breaker.
Table user_subscription_events
| column | type | constraints |
|---|---|---|
| user_id | INTEGER | NOT NULL |
| event_type | VARCHAR(20) | NOT NULL, CHECK (event_type IN ('signup','cancel')) |
| event_time | TIMESTAMP | NOT NULL |
| plan_type | VARCHAR(20) | NOT NULL |
| source | VARCHAR(20) | NOT NULL |
Sample data:
| event_time | event_type | plan_type | source | user_id |
|---|---|---|---|---|
| 2023-05-01 09:03:12 | signup | paid | web | 101 |
| 2023-06-10 14:27:45 | cancel | paid | web | 101 |
| 2023-07-02 08:11:06 | signup | paid | mobile | 101 |
| 2023-05-05 11:55:20 | signup | paid | 202 | |
| 2023-05-07 16:02:09 | cancel | paid | support | 303 |
Expected output
One row per user showing their latest event details and derived current_status. If two events share the same event_time, prefer 'signup' over 'cancel'.
| current_status | latest_event_time | latest_event_type | latest_plan_type | latest_source | user_id |
|---|---|---|---|---|---|
| active | 2023-07-02 08:11:06 | signup | paid | mobile | 101 |
| active | 2023-05-05 11:55:20 | signup | paid | 202 | |
| canceled | 2023-05-07 16:02:09 | cancel | paid | support | 303 |
Hints
- Use
ROW_NUMBER()partitioned byuser_id. - Order by
event_time DESC, then prefer signup before cancel. - Use
TO_CHARin PostgreSQL when a formatted timestamp string is required.
Improve offer-delivery logic
List at least three concrete improvements or safeguards for a Python service that assigns experiment variants and delivers a free-trial offer, focusing on idempotency, deterministic assignment, eligibility, late events, I/O robustness, and data validation.
Table user_subscription_events
| column | type | constraints |
|---|---|---|
| user_id | INTEGER | NOT NULL |
| event_type | VARCHAR(20) | NOT NULL, CHECK event_type IN ('signup','cancel') |
| event_time | TIMESTAMP | NOT NULL |
| plan_type | VARCHAR(20) | NOT NULL |
| source | VARCHAR(20) | NOT NULL |
Sample data:
| event_time | event_type | plan_type | source | user_id |
|---|---|---|---|---|
| 2023-05-01 09:03:12 | signup | paid | web | 101 |
| 2023-06-10 14:27:45 | cancel | paid | web | 101 |
| 2023-07-02 08:11:06 | signup | paid | mobile | 101 |
| 2023-05-05 11:55:20 | signup | paid | 202 | |
| 2023-05-07 16:02:09 | cancel | paid | support | 303 |
Expected output
A set of concrete recommendations that improve safety and correctness when assigning variants and sending offers.
| recommendation |
|---|
| Idempotency: check a delivery/exposure log keyed by (user_id, experiment_id, variant, offer_id) and wrap assignment+send in a transaction to avoid duplicates. |
| Deterministic variant assignment: use hash-based bucketing on (user_id, experiment_id) and persist the assignment to prevent re-randomization. |
| Eligibility gating: only trigger for eligible users (e.g., not active, no prior free trial, correct region/plan) and enforce a cool-off window from last event. |
| Handle late/out-of-order events: compute status by event_time with stable tie-breakers and schedule reconciliations to correct prior decisions. |
| Robust I/O: add timeouts, retries with exponential backoff, and a dead-letter queue; emit structured logs and metrics for monitoring. |
| Data validation: enforce allowed event_type values; quarantine malformed rows; default to a safe no-send behavior on unknowns. |
Hints
- Think about deduplication and transactionality.
- Use stable hashing to assign variants deterministically.
- Gate offers by eligibility and timing; plan for late data and transient failures.