# Bean & Bark: the model becomes the code

You've modelled the store, questioned it, operated it safely, and declared it once as annotated C#. The last step is to **ship** — and here's the payoff Part 2 was building toward: the model from the last chapter becomes the *code your app runs*. You'll add referrals to Bean & Bark, and you'll never write the data layer, the schema, or the constraint twice.

**You'll learn**

- Generate a data-access method from your model — the raw **AWS SDK** form, or the terse **Kanject repository** form
- Ship a real feature with a new **marker** (a unique code) and an **atomic transaction** (dual credit)
- Close the loop — watch the studio read exactly what the app just wrote

> **The ask:** **Nadia:** *"let's do referrals — every customer gets a code, and both people get $5 credit when it's redeemed. can we ship it this sprint?"*

## The model was the code all along

That one annotated model has been the source of truth the whole time — the schema DynoStudio reads, the rulebook the table enforces. Now it's the source of your *code* too. Add `[Unique("ReferralCode")]` to `Customer`, hit codegen on the lookup, and the studio emits ready C# — two ways. Take the raw AWS SDK form when you want zero dependencies and can carry the marker's two-step yourself:

```csharp
// find a customer by referral code — the marker's two-step, by hand
var marker = await ddb.GetItemAsync(new GetItemRequest {
    TableName = "BeanAndBark",
    Key = {
        ["pk"] = new AttributeValue($"$$Unique#ReferralCode#{code}"),
        ["sk"] = new AttributeValue("ReservedData"),
    },
});
if (!marker.Item.TryGetValue("RefHashKey", out var refPk)) return null;

// the marker row already holds the target's full key — you never guess its sk
var found = await ddb.GetItemAsync(new GetItemRequest {
    TableName = "BeanAndBark",
    Key = { ["pk"] = refPk, ["sk"] = marker.Item["RefRangeKey"] },
});
```

…or take the Kanject repository form, where the marker you declared does exactly that work for you:

```csharp
// [Unique("ReferralCode")] generated this — the code IS the argument, the two reads hidden
Customer? referrer = await customers.FindCustomerByReferralCodeAsync(code);
```

Sixteen lines become one call — and it isn't a leaky wrapper hiding something you should worry about. It *is* the `[Unique]` marker from the last chapter, generating its own reserved-row lookup: the `code` you pass is exactly the value the marker keys on. Same model, less to get wrong.

## Ship it — atomically

Redeeming a referral touches two customers: credit the referrer, credit the new one. Either both happen or neither does — anything else means someone got $5 the other didn't. That's a **transaction**. Your endpoint calls the generated repository; DynoStudio previews it executing as a native `TransactWriteItems`, all-or-nothing:

```sql
-- redeem: credit both accounts, all-or-nothing
BEGIN TRANSACTION;
  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500
    WHERE pk = 'CUSTOMER#c-014' AND sk = 'PROFILE';   -- the referrer
  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500
    WHERE pk = 'CUSTOMER#c-207' AND sk = 'PROFILE';   -- the new customer
COMMIT;
```

> **The loop closes:** Deploy it and hit `POST /referral/redeem`. The write lands in the same `BeanAndBark` table you started with — so you can watch both customers' balances change in **Browse** (Part 1), see the marker's reserved rows appear in the studio, and watch the redemptions flow into next quarter's revenue. One dataset, one studio, the whole lifecycle — **build, analyze, operate, model, ship** — closed into a loop. That's the thesis you've been living: the studio sits *upstream* of your database, not beside it.

**Recap**

- Codegen turns an access pattern into ready C# — the raw **AWS SDK** form, or the terse **Kanject repository** form that uses the markers you declared.
- A feature ships with a **marker** (a unique referral code) and a **transaction** (both accounts credited, or neither).
- The studio reads what the app writes: model once, and the schema, the constraints, and the code all agree — no drift, no second definition.

**The last check**

**1. The two generated forms — raw AWS SDK vs the Kanject repository — how do they relate?**

- Both are generated from the same model; the terse one is the marker doing the two-step for you ✓ — they're the same lookup at different altitudes — the repository form isn't a hand-written wrapper, it's the `[Unique]` marker's generated reserved-row read.
- The AWS SDK one is real; the Kanject one is a mock for demos — both are real, runnable code the studio generates. The Kanject form simply hides the reserved-row two-step the AWS form spells out.
- They query different tables — same table, same items — one just carries the marker convention by hand while the other has it generated.

**2. Redeeming credits two customers. How do you guarantee both are credited, or neither?**

- A transaction — it commits both writes together as one TransactWriteItems, or rolls back ✓ — a transaction is all-or-nothing: there's no window where one account is credited and the other isn't.
- Two separate UPDATEs, run quickly one after the other — if the second write fails, the first already committed — one customer is credited and the other isn't. That's exactly what a transaction prevents.
- A GSI that keeps the two balances in sync automatically — a GSI is a read view; it doesn't make two writes atomic. Consistency across writes is what a transaction is for.

**Try it yourself**

**1. Add the referral code**

Add a unique referral code to the `Customer` model from the last chapter, so it both generates a lookup and can never collide.

_Hint:_ It's the same `[Unique(...)]` marker you used for `Email` — one attribute, one property.

_Solution:_ `[Unique("ReferralCode")]` on a `ReferralCode` property generates `FindCustomerByReferralCodeAsync` and guarantees no two customers share a code — a reserved `$$Unique#ReferralCode#…` row makes a duplicate impossible.

```csharp
[Unique("ReferralCode")]
public string ReferralCode { get; set; }
```

**2. Make the credit atomic**

Write the transaction that credits two customers 500 cents each — both, or neither.

_Hint:_ Wrap two `UPDATE ... SET CreditCents = CreditCents + 500` statements (each keyed to a full primary key) in `BEGIN TRANSACTION; … COMMIT;`.

_Solution:_ Two keyed `UPDATE`s inside `BEGIN TRANSACTION; … COMMIT;` execute as one `TransactWriteItems` — all-or-nothing, so a referrer is never credited without the new customer.

```sql
BEGIN TRANSACTION;
  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500
    WHERE pk = 'CUSTOMER#c-014' AND sk = 'PROFILE';
  UPDATE "BeanAndBark" SET CreditCents = CreditCents + 500
    WHERE pk = 'CUSTOMER#c-207' AND sk = 'PROFILE';
COMMIT;
```

> **You've done the whole loop:** From one cheap read to a shipped feature — all on a single coffee-roaster table. You can build a model, answer a business question, operate it in production, and ship code from it. [Transactions](https://www.kanject.com/docs/dynostudio-transactions/) is the full reference for the atomic writes behind this last step. The model you wrote is the schema, the rulebook, and the code — written once, true everywhere.

---
_Source: https://www.kanject.com/docs/dynostudio-bean-bark-ship/ · Kanject Docs_
