# Venture Seed High Table Dashboard

If you opened `/auth` in a browser, stop. Do not click Continue with GFAVIP Wallet. This page is for humans. Agents authenticate with a GFAVIP Wallet bearer as below. Never put a token in a URL.

Securely review portfolio companies, KPI reports, valuations, and portfolio indicators for Venture Seed Venture Studio.

## Discovery

- Application: `https://dashboard.ventureseed.com`
- OpenAPI: `https://dashboard.ventureseed.com/openapi.json`
- Agent card: `https://dashboard.ventureseed.com/.well-known/agent-card.json`
- Human sign-in: `https://dashboard.ventureseed.com/auth`
- GFAVIP headless SSO guide: `https://wallet.gfavip.com/headless_sso.md`

## Authentication

Use a GFAVIP Wallet session bearer created for the acting human or PowerLobster identity:

```http
Authorization: Bearer gfavip-session-REDACTED
```

The dashboard sends the bearer to GFAVIP Wallet's server-side validation endpoint on every request. It trusts only the stable actor identity returned by Wallet. A PowerLobster's `agent_context.owner_id` identifies the owner relationship but never grants or inherits the owner's dashboard role.

Never place a bearer in a URL, request body, log, issue, chat transcript, or source file. Do not send cookies or CSRF headers when using bearer authentication.

## First access and explicit grant

1. Call `GET /api/user` with the actor's bearer.
2. A new valid identity receives `403` with `error: "access_pending"`. This safely records a token-free access request.
3. A Venture Seed administrator reviews the exact Wallet actor and owner IDs in a browser session.
4. For a human with a matching historical account, approval securely links the immutable Wallet identity to that reviewed account, preserving its role, portfolio assignments, reports, and internal ID. When no historical match exists, a browser administrator may instead create a new GFAVIP-only human permission principal with explicit scope.
5. The administrator explicitly selects a new human or agent's dashboard role and portfolio-company roles in the same atomic approval operation. Linking a historical human account does not alter its existing permissions. Selecting `ceo` for a new human also designates that person as the company CEO and fails closed if a different CEO is already recorded.
6. Retry `GET /api/user`. A successful response describes the GFAVIP-backed dashboard principal whose permissions apply.

Approval is not implied by Wallet ownership, a PowerLobster squad, a successful token validation, or the owner's own dashboard access.

## Permission model

Headless callers use the same routes and authorization checks as human users:

- `admin`: global dashboard and administrative operations. Approval of new Wallet identities still requires a browser admin session and cannot be performed with a bearer.
- `general` + company `viewer`: read that assigned company; cannot submit KPI reports or write cases.
- `general` + company `ceo` or `editor`: read that assigned company; submit monthly KPI reports; create/update cases and append case log entries.
- no company assignment: no access to that company's data.

Do not assume access. Discover it from `GET /api/businesses` and treat `403` as authoritative.

### Discover company role and write capability

`GET /api/businesses` and `GET /api/businesses/{businessId}` include access fields for the **calling principal** on each company:

| Field | Meaning |
|---|---|
| `companyRole` | `admin`, `ceo`, `editor`, `viewer`, `contributor`, or `null` |
| `canSubmitReports` | May submit/revise monthly KPI reports |
| `canWriteCases` | May create cases, update case metadata, append log entries |

Global admins receive `companyRole: "admin"` with both write flags `true` for every business. Agents should use these flags instead of probing with test writes.

Example business list item (fields abbreviated):

```json
{
  "id": "…",
  "name": "Easy China Warehouse",
  "companyRole": "editor",
  "canSubmitReports": true,
  "canWriteCases": true
}
```

## Recommended agent workflow

1. Authenticate with `GET /api/user`.
2. Read `GET /api/businesses` to obtain authorized companies **and** each `companyRole` / `canWriteCases` / `canSubmitReports`.
3. For strategy context, list open cases with `GET /api/businesses/{businessId}/cases?status=open` and load detail, recommendations, and entries before advising.
4. Read existing reports using `GET /api/businesses/{businessId}/reports` before proposing KPI changes.
5. Present the intended company, month, KPI values, and progress note to the human operator.
6. Write only after explicit human instruction using `POST /api/businesses/{businessId}/reports` (requires `canSubmitReports`).
7. Read the created report back and report its ID, version, status, and provisional flag. New submissions are `pending` until an administrator reviews them.
8. Append case updates or propose recommendations only when `canWriteCases` is true and the operator asked for the write.
9. Treat recommendations as advisory handoffs. Do not invent assignees, operational deadlines, dependencies, or subtasks; the company chooses where execution is managed.

## Strategy case logs

Cases are company-scoped strategy discussion threads (creative consulting input, open decisions, follow-ups). They replace Google Sheets/Docs case logs. Content is intended for the company CEO—there is no studio-only visibility tier.

Recommendations inside a case provide a deliberately small response workflow: `proposed → acknowledged → accepted → completed`, with `declined` available before completion. `Acknowledged` means the advice was seen; `accepted` means the company intends to carry it into its own operating system. Venture Seed does not track operational assignees or project dependencies. A case has one optional next Venture Seed review date, which is not a task due date.

**Permissions (same for humans and headless agents):**

- Read: any principal with access to the business (admin, or company assignment including `viewer`).
- Create case / update case / append entry: when `canWriteCases` is true (`admin`, or company `ceo` / `editor`).

**Discovery and context:**

```http
GET /api/businesses/{businessId}/cases
GET /api/businesses/{businessId}/cases?status=open
GET /api/businesses/{businessId}/cases/by-code/{caseCode}
GET /api/cases/{caseId}
GET /api/cases/{caseId}/entries?order=desc
GET /api/cases/{caseId}/actions
GET /api/cases/{caseId}/export
```

**Writes (same API as the browser UI):**

```http
POST /api/businesses/{businessId}/cases
PATCH /api/cases/{caseId}
POST /api/cases/{caseId}/entries
POST /api/cases/{caseId}/actions
PATCH /api/case-actions/{actionId}
```

Example create body:

```json
{
  "title": "Yiwu expansion",
  "priority": "high",
  "summary": "Warehouse and market options in Yiwu",
  "initialEntry": {
    "body": "Kickoff: map locations and partner intros.",
    "entryType": "update"
  }
}
```

Do not send `caseCode`. The server always assigns the next sequential code from the company’s `caseCodePrefix` (e.g. `ECW001`, `ECW002`). Admins set the prefix on the business (settings / edit business). If unset, the first case derives initials from the company name and stores them.

Example append entry:

```json
{
  "entryDate": "2026-08-05",
  "body": "Reviewed social video tools Mike suggested for Sia posts.",
  "entryType": "idea"
}
```

Author is always the authenticated principal. Prefer reading open cases before strategic advice so recommendations stay grounded in existing decisions.

Example recommendation and company response:

```http
POST /api/cases/{caseId}/actions
Content-Type: application/json

{"body":"Revise the homepage quote paths for B2B, storage, D2C, and FBA."}
```

```http
PATCH /api/case-actions/{actionId}
Content-Type: application/json

{"status":"accepted","responseNote":"Copied into the company backlog for the next website release."}
```

Completion or decline requires a short outcome/reason note. Every status change is also appended to the case record. The Markdown export includes context, recommendations, company responses, and the full case record for copy/paste into the company’s chosen tools.

Example report body:

```json
{
  "reportMonth": "2026-07",
  "kpiData": {
    "Monthly Revenue": 125000,
    "Gross Profit": 48000,
    "OPEX": 31000
  },
  "progressNote": "July close reviewed with the company operator.",
  "provisional": false,
  "mode": "submit"
}
```

KPI keys vary by company. Read the company's `kpiDefinitions`; `kpiData` must contain exactly those canonical keys with finite numeric values. Do not invent, omit, or silently rename KPI fields. Set `provisional: true` whenever any value is unverified; provisional reports cannot be approved.

## Reporting integrity and revisions

- One report record is allowed per business and month. A duplicate submission returns `409`.
- Reports are never hard-deleted. Corrections use `PUT /api/reports/{reportId}` with the complete canonical KPI set, progress note, provisional flag, and a required revision reason.
- A revision increments `version`, preserves the prior immutable snapshot, and returns a non-draft report to `pending` review.
- Read `GET /api/reports/{reportId}/history` to verify revision and workflow events.
- Only approved, non-provisional reports affect portfolio totals and analytics.
- Approval decisions are guarded. Administrators may approve a pending verified report, reject it with a reason, or return it as `needs_review` with correction instructions.

## Authentication responses

- `401 invalid_token`: bearer is missing, malformed, invalid, or expired. Obtain a fresh bearer from Wallet.
- `403 access_pending`: identity is verified but has not been explicitly approved.
- `403 access_denied`: the request was denied.
- `403 local_access_denied` or route-level `403`: internal identity link, role, owner relationship, or company permission does not allow the operation.
- `503 wallet_unavailable` or `503 authentication_unavailable`: validation could not complete safely. Stop and retry later; never bypass Wallet validation.
- `429 too_many_headless_requests`: wait for the response rate-limit window before retrying.
- `404 api_not_found`: the API path is not implemented; re-read the OpenAPI document instead of guessing routes.

## Safety rules

- Default to reading and proposing. Make data changes only when the operator explicitly asks.
- Before writing a KPI report, confirm the company, reporting month, currency/unit, and values.
- Never claim a write succeeded until the API returns success and the result has been read back.
- Do not use an owner's bearer for an agent. Each actor uses its own Wallet/PowerLobster bearer and its own explicitly approved dashboard permission principal.
- Never attempt to approve, assign, elevate, or relink identities through headless access.
