# CLAUDE.md

This file provides guidance to Claude Code when working with the **P2HS Core API** repository.

## What this repo is

**P2HS Core API** is the control plane for the P2HS platform.

It owns:

- auth and sessions
- workspaces, membership, RBAC, and tenant isolation
- projects, instructions, prompt sessions, codegen orchestration
- revisions, previews, deployments, domains
- billing, entitlements, metering, credits, top-ups
- secret / env-variable custody and propagation policy
- authoritative authorization for **P2HS Cloud**

It does **not** own the async execution fabric, record engine, provider dispatch, or D1/R2/Queue wiring. Those belong to the separate **P2HS Cloud** repo/runtime (`E:\workroom\2026\P2HSCloud`).

## Working assumptions

When modifying this repo, preserve this rule:

> **Core decides; Cloud executes.**

That means:

- entitlement logic stays in Core
- billing state stays in Core
- project/workspace ownership checks stay in Core
- capability enablement stays in Core
- secret scoping / distribution policy stays in Core
- P2HS Cloud should receive authorization results, not become the source of truth for policy

---

## Commands

```bash
# Install dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt

# Run API server
uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload

# Run background worker
arq src.workers.main.WorkerSettings

# Database migrations
alembic upgrade head
alembic revision --autogenerate -m "description"
alembic downgrade -1

# Tests
pytest
pytest tests/test_auth_onboarding_billing.py
pytest tests/test_billing_metered.py::test_name

# Lint / architecture
ruff check src/
import-linter
```

There may not always be full test coverage for new slices. Prefer adding or updating targeted tests when changing billing, auth, worker orchestration, or cloud contract logic.

---

## Architecture overview

**P2HS** is a DDD-oriented modular monolith using FastAPI + PostgreSQL + Redis.

### Request lifecycle

1. FastAPI routes receive HTTP requests
2. Dependencies inject DB session, Redis, current user/service principal
3. Services contain business logic
4. Repositories encapsulate data access
5. Long-running or retryable work is enqueued to arq workers

### Background worker model

Heavy operations must not block request handlers.

Typical worker slices include:

- project setup / repo provisioning
- AI codegen runs
- build / preview preparation
- deployment orchestration
- webhook reconciliation
- deferred billing or cleanup flows
- Cloud project bootstrapping (`src/workers/tasks/cloud_sync.py`)

Workers should be resumable or idempotent where feasible.

---

## Domain structure

Each bounded context under `src/domain/` should generally follow this shape:

```text
<domain>/
├── models.py
├── schemas.py
├── repository.py
├── service.py
├── router.py
└── facades.py
```

Keep responsibilities separated:

- **router.py** — transport mapping only
- **schemas.py** — request/response DTOs
- **service.py** — business logic and orchestration
- **repository.py** — persistence/data access
- **facades.py** — explicit cross-domain access when needed

Do not put durable business logic into routers.

---

## Key bounded contexts

Important domains include:

- `auth`
- `workspaces`
- `projects`
- `instructions`
- `codegen`
- `revisions`
- `previews`
- `deployments`
- `billing`
- `api_keys`
- `artifacts`
- `hosting`
- `github_webhooks`

When adding new functionality, prefer extending an existing bounded context if ownership is clear. Create a new one only when the behavior is substantial and cohesive.

**Feature Packs, App Blocks, and Starter Library** follow a frozen composition contract. Before adding or updating any of those, read [docs/FEATURE_PACKS_APP_BLOCKS_STARTER.md](docs/FEATURE_PACKS_APP_BLOCKS_STARTER.md). Before adding a connector, capability, or integration family, read [docs/P2HS_PLATFORM_EXTENSION_STANDARD.md](docs/P2HS_PLATFORM_EXTENSION_STANDARD.md).

---

## Core ↔ Cloud contract

This repo must support the P2HS Cloud internal contract. The integration client lives at `src/integrations/cloud_control_client.py` and the bootstrap worker task at `src/workers/tasks/cloud_sync.py`.

### What Core pushes to Cloud (control plane sync)

Core calls Cloud's internal control endpoints to keep Cloud's D1 cache in sync:

- `PUT /v1/cloud/control/workspaces/:id` — workspace status, plan slug
- `PUT /v1/cloud/control/projects/:id` — project status, allowed request types, origins
- `PUT /v1/cloud/control/clients/:id` — trusted client, allowed origins + capabilities
- `PUT /v1/cloud/control/projects/:id/capabilities` — capability flags
- `PUT /v1/cloud/control/integrations/:project_id:provider` — integration config
- `PUT /v1/cloud/control/bootstrap/project/:id` — atomic upsert of all of the above

These are internal, token-authenticated, and idempotent. Retries are always safe.

### What Cloud calls Core for (authorization + usage)

#### `POST /v1/cloud/authorize`

Purpose: validate whether a cloud job request is allowed, and return the grant data Cloud needs to execute safely.

Typical validations:

- workspace/project ownership
- project/client relationship
- current subscription state
- feature/capability enabled
- required integration credentials configured
- usage allowance / credits / plan limits

#### `POST /v1/cloud/usage/finalize`

Purpose: reconcile final billable usage for a completed cloud job. Updates ledgers, allowances, usage counters, and audit trail.

#### `POST /v1/cloud/usage/release`

Purpose: release reserved usage for failed/canceled/non-billable requests. Prevents double-charging.

These endpoints are internal, authenticated, and must be idempotent.

### What Cloud owns (Core does NOT touch)

- The record engine (entities, records, relations, field index) is fully owned by Cloud
- Core does not read or write `cloud_entities`, `cloud_records`, `cloud_record_relations`, or `cloud_record_field_index`
- Core does not need to know the schema or content of individual records
- If Core needs to reference a cloud record, it uses the `project_id` + `record_id` as opaque identifiers

---

## Critical architectural rules

### 1. Keep Core authoritative for Cloud policy

Any endpoint used by P2HS Cloud must enforce Core as the source of truth for:

- project/workspace ownership
- plan and billing state
- capability enablement
- usage reservation/finalization/release
- secret availability and integration status

Do **not** move business policy into Cloud just because Cloud performs execution.

### 2. Keep tenant isolation explicit

Every project mutation or project-derived read must verify the workspace boundary.

Avoid "lookup by ID only" patterns unless the ID is already proven to belong to the caller's workspace.

### 3. Secrets are policy-controlled assets

Core should own:

- secret metadata
- scope and allowed targets
- propagation intent
- audit trail
- rotation / revocation behavior

Do not expose raw project/provider secrets to browser clients.

### 4. Heavy operations belong in workers

Anything involving GitHub, AI coding, builds, deploys, external retries, or expensive reconciliation should go through workers unless there is a compelling reason not to.

### 5. Preserve resumability and idempotency

Project setup, deployment, billing reconciliation, and Cloud usage flows are all sensitive to duplicates and partial failure.

Prefer "resume from last completed layer" behavior over destructive retries.

---

## Secret and env-variable flow

A major responsibility of Core is managing where project secrets are allowed to go.

### Possible targets

A project secret may need to be distributed to one or more of:

1. **P2HS-hosted runtime** for the generated app
2. **P2HS Cloud** for backend/deferred execution
3. **connected external Git repository** as a repository secret

### Rules

- scope at least by workspace + project
- record what the secret is for
- record where it is allowed to flow
- do not expose cloud/provider credentials to the browser
- prefer generated apps calling controlled backend capabilities instead of reading secrets directly
- log propagation / rotation / revocation actions

When editing project/env functionality, assume future support for selective distribution per target.

---

## Generated app integration model

Generated apps should usually consume platform capabilities through SSR/BFF routes or approved trusted-client flows.

### Preferred

- SSR/BFF route on the generated app
- server-side auth/session context
- calls Core or Cloud without exposing implementation details

### Allowed with care

- direct browser → Cloud through trusted-client handshake and origin validation
- only when the client is explicitly registered and the action does not require exposing secrets

Never design a flow that requires embedding third-party credentials in frontend code.

---

## AI/codegen guidance

This repo orchestrates AI-powered code generation but should remain provider-agnostic at the domain layer.

Supported provider families include:

- OpenAI
- Cursor CLI
- Claude Code

Guidelines:

- keep provider-specific behavior in integration/adaptor layers
- keep prompt assembly logic centralized
- avoid leaking provider assumptions into unrelated domains
- runs should persist structured status/timeline data for UI aggregation

---

## Billing guidance

Billing is a load-bearing domain. Be conservative.

Core owns:

- plans and product catalog mapping
- workspace subscription state
- usage allowances and credits
- top-ups / purchases
- Stripe webhook reconciliation
- notification dedupe and billing events

When changing billing logic:

- preserve idempotency
- avoid race conditions
- prefer explicit transaction boundaries
- protect metering paths from double-finalization

Cloud may report usage, but Core is authoritative.

---

## Data and persistence guidance

- SQLAlchemy 2 async ORM + Alembic migrations
- use repository methods for non-trivial access paths
- keep migrations forward-safe and review indexes/constraints carefully
- partial unique indexes and advisory locking patterns are acceptable when needed for correctness

Do not make schema changes without adding a migration.

---

## Configuration guidance

Primary config lives in `src/config.py`.

Key groups include:

- `DATABASE_URL`, `REDIS_URL`
- `JWT_*` / session
- `GITHUB_APP_*`
- `STRIPE_*`
- `CLOUDFLARE_*`
- `AI_PROVIDER`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`
- `cloud_control_api_url` — URL of the P2HS Cloud gateway (for pushing control plane updates)
- `cloud_internal_token` — Must match `INTERNAL_CONTROL_TOKEN` in Cloud workers

Do not hard-code environment-specific URLs, secrets, or plan constants in domain logic.

---

## Editing guidance for Claude Code

When implementing a change:

1. identify the owning domain
2. keep router/service/repository boundaries intact
3. update schemas and validations first
4. add or update worker tasks if the flow is asynchronous
5. add migration if persistence changes
6. update internal contract docs if Core↔Cloud behavior changes
7. preserve backward compatibility unless the change explicitly migrates callers

### Prefer

- explicit service methods
- typed request/response schemas
- small facade surfaces between domains
- idempotent write paths
- auditability for secrets, billing, and deployment actions

### Avoid

- fat routers
- bypassing workspace ownership checks
- embedding entitlement logic into Cloud-specific adapters
- returning raw secrets to frontend consumers
- cross-domain imports that skip established facades/helpers

---

## Mental model

Think in three layers:

1. **Core API** — policy, tenancy, orchestration, billing, source of truth
2. **P2HS Cloud** — async execution fabric, record engine, provider/webhook handling
3. **Generated app runtime** — user-facing SSR/frontend layer consuming approved platform capabilities

Preserve those boundaries in every change.
