Orientation
New here? This site is the internal explainer for PulseAd and its product. This page is the reading path; follow it in order and you’ll have a working mental model in about fifteen minutes.
Anchor on these two facts first
Section titled “Anchor on these two facts first”Almost every confusion traces back to one of these:
- The names overlap. PulseAd (company/platform) ≠ Pulson (the product) ≠
PULSEAD(the main Snowflake schema) ≠ PSM (the legacy chat engine) ≠ AOP (the internal operator tool). Internal API paths still use/pulsy/...; that is an implementation namespace, not the product name. The name map untangles all of it — read it before anything else. - Pulson reads freely, but changes never bypass approval. A customer request is routed to the operator owner; an internal/operator session must confirm the target and value before irreversible execution. The whole gate model is in Capabilities.
First-use checklist
Section titled “First-use checklist”- Finish your profile. Sign in through the app’s welcome flow and complete the
profile form.
PUT /pulsy/meupdates the profile;GET /pulsy/meis the useful read-back because it includes completion flags, memberships, pending invitations, and the current team/country scope. - Create or select a team.
GET /pulsy/teamslists your active memberships. If your account is allowed to create one,POST /pulsy/teamscreates a team;POST /pulsy/teams/{team_uuid}/switchselects the current team and returns a refreshedMeresponse. A missing current team is a real blocked state, not an invitation to guess a team ID. - Set the country together with the team. Use
POST /pulsy/me/contextwhen you need an explicit scope. It validates both membership and the team’s country catalog, normalizes the ISO-3166 alpha-2 code to uppercase, and returns422for an unknown membership, unavailable country, or team with no countries. - Verify account visibility before asking for ad data.
GET /pulsy/me/connectionsis intentionally fail-closed when either current team or current country is missing. The/pulsy/chatsroute uses the server-side current scope; a bodyteam_iddoes not override it. Missing team context is rejected asTEAM_CONTEXT_REQUIRED(400), and an incomplete country scope is rejected asCURRENT_SCOPE_INCOMPLETE(409). - Choose report language if needed. App display language and report-generation
language are separate settings.
POST /pulsy/me/report-localepersistskooren; other values are rejected with422.
Team management that matters
Section titled “Team management that matters”GET /pulsy/teams/{team_uuid}/membersreturns a cursor-paginated page, not a bare list: useitems,next_cursor,has_more, andtotal_count(defaultlimit20, maximum 100).- Team admins manage member roles and invitations. The server prevents a user from changing their own role, so a UI-level role control is not a substitute for admin access.
GET /pulsy/teams?include_hidden=trueis for settings visibility; the default team list contains active memberships only.
The reading path
Section titled “The reading path”- What PulseAd is — the company, the name map, the product surfaces, and the one behavioral rule. Start here.
- Capabilities — what Pulson can read vs. change, and the approval gates every write passes (including the pilot-only live path).
- Data model — what Pulson knows: the six analysts over Snowflake, and how current the data is.
- Data & coverage — which channels are covered, Amazon vs. the manual off-Amazon upload.
- Creative — the image and video generation tools.
- Reference + the glossary — the terms the rest of the docs assume.
How these docs work (so you can trust them)
Section titled “How these docs work (so you can trust them)”- They’re derived from the live source repos, pinned to the commit they were
generated from, and re-syncable. The full procedure and writing rules are in
AGENTS.md. - They document the truth candidly — including legacy surfaces and known gaps — because this is internal. If you find something asserted that the code doesn’t support, that’s a bug; flag it.
- Found a gap the docs can’t answer? Open questions and “verify with ops”
items live in
_internal/needs-johnny.md— add to it rather than guessing.