---
title: Onboarding
sort: 1
tags: [people-ops]
---

# Onboarding

Your first week at ZephyrCart, in checklist form. Your buddy and your manager are responsible for
unblocking you when something here is wrong.

## Day 1

- [x] Laptop arrived. (If not — ping People Ops on `#peopleops`.)
- [ ] SSO works for Google Workspace, Slack, GitHub, Linear.
- [ ] 1:1 booked with your manager.
- [ ] You've been added to your team's Slack channel and the company-wide `#announcements`.

## Day 2–3

- [ ] You've read the [team handbook](team-handbook.md) end to end. It's short.
- [ ] You've read the [code of conduct](policies/code-of-conduct.md). Signed acknowledgment goes to
      People Ops.
- [ ] You've cloned the `zephyrcart/platform` monorepo and run the local stack against a test
      tenant. Your buddy can pair on this if the bootstrap script falls over.

## Week 1

- [ ] You've shipped one small change to production. "Small" can be a typo fix; the point is to
      walk through the deploy pipeline once with someone watching.
- [ ] You've attended one all-hands and one of your team's weekly syncs.
- [ ] You've met the people listed in your `who-to-know.md` (your buddy will send this).

## When you get stuck

The single best move is to post the question in your team channel before slacking individuals
directly. We bias toward asynchronous, searchable answers — see the
[communication norms](team-handbook.md#communication) in the handbook.


---

---
title: Team Handbook
sort: 2
tags: [people-ops, reference]
---

# Team Handbook

How we work at ZephyrCart. If something here disagrees with what your manager told you, your
manager is right and this page is out of date — please open a PR.

## Who we are

A 64-person company headquartered in Copenhagen, with offices in Berlin and Lisbon and remote
teammates in Singapore, Toronto, and Cape Town. The org tree lives in BambooHR; the source of
truth for who's on what team is the `#team-*` Slack channels and the squad map below.

## Squads

- **Storefront API** — owns `/v1/carts`, `/v1/checkouts`, `/v1/orders`. Lead: Ali.
- **Catalog** — owns `/v1/products`, `/v1/collections`, search. Lead: Ali.
- **Tax & Money** — owns calculation engines, currency, refunds. Lead: Ali.
- **Platform** — owns the build, deploy, observability, the dev portal. Lead: Ali.
- **Growth Eng** — owns the marketing site, signup, billing portal. Lead: Ali.

## Communication

We bias hard toward written, asynchronous, searchable. Three rules of thumb:

1. If more than two people care about it, put it in a channel, not a DM.
2. If you'd say it in a meeting, write it down before the meeting.
3. If a thread is more than ten replies long, write a doc.

Meetings are the most expensive way to make a decision. Defaults: cameras off, agenda required,
notes shared within 24 hours.

## How we ship

- Trunk-based development on `main`. Feature flags for anything user-visible.
- Code review by one engineer on the owning squad; design review by an EM for changes that touch
  the API surface or the data model.
- Production deploys are continuous and automated. Rollbacks are one Slack command.

## Calendars and time off

The platform team owns the on-call rotation; everyone else's calendar is their own. Time off goes
in BambooHR a minimum of one week in advance (more if it's longer than a week). Public holidays
follow your home country's calendar.


---

---
title: Stripe Tax integration partnership
sort: 99999508
tags: [product, partnerships]
author: Ali
---

# Stripe Tax integration partnership

The integration that's been in technical preview since March is now generally available, and
Stripe added us to their app gallery this morning. Marketing post lands tomorrow; this is the
internal one.

## What ships

A per-tenant toggle to delegate US sales-tax (and a few other non-EU jurisdictions) calculation
to Stripe Tax instead of our internal engine. Customer-visible benefit: nexus and economic
threshold tracking that we never planned to build ourselves.

Public documentation: [Stripe integration](../../dev-docs/integrations/stripe.md).

## Commercial

This is a referral arrangement, not a revenue share. The contract sits with Ali in
`#legal-archive` if you need to see it.

## What changes for internal teams

- **Support:** the runbook for "why is the tax wrong?" now branches on `tax_calculation_source`.
  Updated in the support wiki.
- **Tax & Money:** the team owns the integration. Stripe Tax outages do not page us; they fall
  back to internal calculation.
- **Sales:** new talking point for the US mid-market — see the updated battle card.

Drinks Thursday in Lisbon. Talk to Ali if you can fly down.


---

---
title: All-hands recap — May 15
sort: 99999515
tags: [allhands]
author: Ali
---

# All-hands recap — May 15

For anyone who couldn't make it live. Recording in `#allhands` for the next 30 days.

## Q2 numbers

Two numbers from the founder slide that aren't on the dashboard yet:

- ARR closed April at €12.1M, up 47.2 % year-over-year (the slide had €11.8M — corrected post-meeting).
- Net dollar retention sits at 118 %, lifted by the Stripe Tax handoff feature finally landing
  enterprise upsells we'd lost in 2025.

## OKR check-in

Of the 14 company OKRs for Q2, 4 are green, 7 are amber, 3 are red. The red ones:

1. "Cut catalog import latency by 50 %" — still at 18 % improvement. The catalog team revised the
   plan; new ETA is end of June.
2. "Launch Brazil region" — slipped to Q3 because of regulatory complexity around Pix.
3. "Ship the new dashboard's customer-merge UI" — held back behind the data-handling policy
   review (see [Data handling](../policies/data-handling.md)).

Amber is fine. Red is something we'll talk about in the next manager forum.

## Q&A highlights

- **On office time:** the working group lands a recommendation by June 15. The honest answer
  remains "we trust your judgement."
- **On the hiring freeze:** still on for non-platform roles through Q2. Reopens in July if Q2
  closes on plan.
- **On the all-hands cadence:** moving to monthly (last Thursday) instead of every three weeks.

Slides are pinned in `#allhands`.


---

---
title: ap-singapore is now GA
sort: 99999522
tags: [platform, launch]
author: Ali
---

# ap-singapore is now GA

The Singapore region exited beta on Monday. SLA, latency targets, and on-call coverage are now
production-grade. The full list of tenants that moved is in `#launch-apac`.

## What this means for you

- **Storefront API:** route customers to `ap-singapore` if they're east of the Bay of Bengal. p50
  from Sydney drops from 220 ms (to Frankfurt) to 75 ms (to Singapore).
- **Tax & Money:** the Singapore region inherits the existing tax zones; nothing else to do for
  GST.
- **Platform:** on-call shadow rotation starts next sprint. Sign up at `go/oncall-apac`.

## What it does not mean

- The catalog is still global; switching a tenant's region requires a real migration.
- No automated cross-region failover. See the [deployment topology](../../dev-docs/architecture/deployment-topology.md).

Champagne in the Copenhagen kitchen Friday 16:00 if you're around.


---

---
title: Platform update — May rollups
sort: 99999529
tags: [platform, release]
author: Ali
---

# Platform update — May rollups

Three things shipped this month that are worth knowing about even if you don't work on the
platform team.

## Build pipeline cut to under 6 minutes

The platform team rewrote the test sharding for `zephyrcart/platform`. Cold builds now finish in
5m40s p50 instead of 12m. The savings come from running integration tests in parallel against
per-shard ephemeral PostgreSQL containers. Detail: `PR #14228`.

## Frankfurt region capacity doubled

Customer growth in DACH pushed Frankfurt utilisation above 60 % at peak. We doubled the API tier
and the PostgreSQL read replicas. No customer-visible change; latency p99 dropped from 92 ms to
71 ms.

## Lucene index for product search rebuilt

The new schema indexes `metadata.*` fields if their key starts with `searchable_`. Catalog teams,
you may now ship the metadata-as-facets work that was blocked on this.

— Ali


---

---
title: Friday-afternoon shipping window — opt-out next sprint
sort: 99999530
tags: [process]
author: Ali
---

# Friday-afternoon shipping window — opt-out next sprint

The "no deploys after 14:00 Friday" rule has been in place for two years. It catches a real class
of weekend incidents, but it also burns Friday afternoons for teams that ship low-risk PRs.

Starting next sprint, the policy becomes opt-in per service:

- Default behaviour is unchanged — the deploy pipeline blocks production deploys after 14:00 local.
- A service can opt out by adding `friday_afternoon_deploys: allowed` to its `service.yaml`.
- Opting out requires the owning EM's signoff (the file enforces an EM-only CODEOWNER for that key).

Two reasons we're loosening it now: trunk-based CI catches regressions earlier than it did in 2024,
and the on-call rotation has full APAC coverage so a Friday deploy isn't a EU-only burden.

If your team wants to opt out, the PR template is in `runbooks/opt-out-friday.md`.


---

---
title: Code of conduct
sort: 1
tags: [policy]
---

# Code of conduct

What we expect of each other at ZephyrCart. Short, on purpose.

## Be kind, candid, and specific

Disagree with the work, not the person. "This API name is confusing because…" is the shape; "you
made a confusing API" is not. Candid feedback is a gift; vagueness wrapped in politeness is not.

## Assume good intent. Verify if you can't.

If a colleague did something that surprised you, ask before reacting. The asynchronous, written
default helps here — re-read the slack message before responding.

## Respect boundaries

People's time, attention, and on-call windows are theirs. Don't ping outside business hours
unless it's actually urgent. "Actually urgent" means "customers are affected and you've already
paged on-call."

## No harassment, ever

Harassment in any form — sexual, racial, religious, age-based, anything — is grounds for
termination. There is no grey area. If you witness it or experience it, contact your manager,
People Ops, or one of the two designated trust contacts (listed in BambooHR). Reports are
confidential.

## Conflicts of interest

If you have a financial relationship with a customer, a competitor, or a vendor, disclose it in
writing to People Ops. The default response is "thank you for telling us, here's how to recuse
yourself." It is almost never "you have to give it up."

## How this is enforced

The first response is always a private conversation. Repeated or egregious breaches escalate to
formal warnings and, ultimately, termination. The trust contacts maintain an anonymised record of
patterns; they share it with the founders quarterly.

You acknowledge this code as part of [Onboarding](../onboarding.md). Signed acknowledgments live
in BambooHR.


---

---
title: Data handling
sort: 2
tags: [policy, compliance]
---

# Data handling

How customer data moves, who can touch it, and what we never do with it.

## Classification

Every piece of data we handle falls into one of four buckets:

| Class           | Example                                       | Storage              | Access                          |
|-----------------|-----------------------------------------------|----------------------|---------------------------------|
| Public          | Marketing copy, API spec                      | Anywhere             | Everyone                         |
| Internal        | This intranet, OKRs                           | SSO-gated tools      | All employees                    |
| Confidential    | Customer email, order data, payment metadata  | Tenant region only   | Role-gated, audited              |
| Restricted      | PAN, CVV (not stored), employee compensation  | Vault, KMS-encrypted | Two-person rule, logged          |

## What stays in the tenant's region

A tenant's `Confidential` data does not leave its home region. There is no cross-region read
replica of customer PII. Telemetry that flows centrally is de-identified at source and listed
explicitly:

- Request counts, latencies, error rates, by route + status
- Aggregate billing totals, by tenant id (not by customer id)
- Webhook delivery success rates, by endpoint host (not by URL path)

What does **not** flow centrally: customer emails, names, addresses, order line items, payment
tokens, IP addresses.

## Access requests

Customer-data access for support requires:

1. An open support ticket from the customer's verified contact.
2. A manager approval click in the access tool. Approvals expire after 24 hours.
3. The query runs against the tenant's region. The audit log captures who, when, what, why.

<div class="text-muted">Raw HTML passes through the renderer — this paragraph demonstrates that.</div>

## What we never do

- Sell, lease, share, or otherwise transmit customer data to third parties for marketing.
- Train models on identifiable customer data. (Aggregate, anonymised telemetry is fair game for
  internal product analytics.)
- Store full card numbers (PAN). Stripe holds the cards; we hold a tokenised handle.

## In a breach

The first action is the [incident response runbook](incident-response.md). The second is the
legal hold and notification — Legal owns this and will direct.

## Audits

We run a third-party penetration test annually (currently with Trail of Bits) and an internal
red-team exercise quarterly. Findings land in the security channel within 30 days of the
engagement closing.


---

---
title: Incident response
sort: 3
tags: [policy, oncall]
---

# Incident response

Read this before your first on-call shift. The runbook lives in the platform repo at
`runbooks/incident.md`; this page is the policy and the mental model.

> **You will not be punished for declaring an incident that turned out not to be one.** The cost
> of false positives is small; the cost of false negatives is missed pages, frustrated customers,
> and unanswered status pages.

## Severity ladder

| Severity | Examples                                                                 | Who pages, who joins                       |
|----------|--------------------------------------------------------------------------|--------------------------------------------|
| SEV-1    | Region down. Payment provider down across multiple tenants. Data breach. | All platform on-call + EM on-call + founder on-call |
| SEV-2    | One service unhealthy, customer-visible degradation, no data loss.       | Service owner + platform on-call           |
| SEV-3    | Internal degradation, no customer impact.                                | Service owner only                         |

## Start the incident

```bash
zephyr incident open --sev 2 --summary "Checkout p99 elevated in eu-frankfurt"
```

The CLI creates the Slack channel, the status page entry, and the Linear ticket. It pages the
right rotation. It pins the runbook in the channel.

## During the incident

Three roles, even for a small SEV-2:

- **Incident commander (IC)** — owns the timeline, the decisions, the channel. Not necessarily
  the most technical person; the calmest one.
- **Comms** — owns the status page, the customer email, the after-action announcement. Often the
  EM.
- **Investigator(s)** — the people in the code. Usually two; one drives, one rubber-ducks.

Status updates land in the channel and on the status page every 15 minutes minimum, even if the
update is "still investigating." Silence is worse than bad news.

## After the incident

A blameless post-mortem within 72 hours, drafted by the IC, reviewed by the team. The template
lives at `runbooks/post-mortem-template.md`. It goes in the platform repo, not on the intranet —
post-mortems are searchable engineering knowledge, not internal politics.

The post-mortem closes with one or more **action items**, each owned by a named person and
ticketed in Linear with a "post-mortem" label. If none ever ship, escalate that pattern.

## Customer communication

For SEV-1 and SEV-2 we send a customer email within 24 hours of resolution. The template is in
`comms/incident-email-template.md`. Tone: factual, brief, no marketing language. Apologise once.

## Out of hours

The on-call rotation crosses time zones so there is always someone awake. If the page rings and
nobody answers within 5 minutes, the escalation flow pages the next person in the rotation. If
the second person doesn't answer within 5 more, the EM on-call is paged. If they don't answer,
the founder on-call is paged. The chain is unbroken for a reason.
