Core Docs

Console Architecture

Console Architecture



core.console is the unified management plane and API gateway for the UNVRSL platform. It replaces direct client-to-service communication with a single-entry-point model.

> Status: Architecture defined. Implementation pending.

Why core.console Exists



The original architecture had clients talking to each core service independently via its own subdomain. This created several problems:

  • N connections per project — every new app needed manual configuration across each service

  • Scattered auth — each service had its own allowlist and access control

  • No unified logging — usage data spread across services

  • Hard to add new services — any new core repo meant updating every client

core.console solves this by becoming the single entry point. Clients get one API key from the console; the console routes to internal services.

Three-Layer Model



core.console follows the same pattern as Google Cloud's architecture:

┌─────────────────────────────────────────────────┐
│ core.console │
├─────────────────────────────────────────────────┤
│ │
│ Layer 1: Management Plane (UI + API) │
│ ┌─────────────────────────────────────────┐ │
│ │ • Dev user & organization management │ │
│ │ • Project CRUD + ownership transfers │ │
│ │ • API key generation (scoped) │ │
│ │ • Service enablement per project │ │
│ │ • Stats dashboards + request logs │ │
│ │ • Billing management │ │
│ │ • Account management (SSO entry point) │ │
│ └─────────────────────────────────────────┘ │
│ │
│ Layer 2: API Gateway (runtime) │
│ ┌─────────────────────────────────────────┐ │
│ │ • API key validation │ │
│ │ • Permission checking │ │
│ │ • Quota enforcement │ │
│ │ • Request routing to internal services │ │
│ │ • Request logging + stats aggregation │ │
│ │ • Rate limiting │ │
│ └─────────────────────────────────────────┘ │
│ │
│ Layer 3: Routes to → core.auth, core.storage, │
│ core.ai, core.hypermedia │
│ (core.assets is a public CDN — │
│ not routed through the console) │
│ │
└─────────────────────────────────────────────────┘


User Model



Dev Users



Not every core.auth user is a developer. A dev_user profile is created the first time a user accesses core.console — they accept terms and choose a username (pre-filled from their auth profile, but changeable).

core.auth user (authentication, sessions, quotas)

└── dev_user (1:1, created on first console visit)
├── owns projects directly
└── member of organizations


The dev_users table links to core.auth.users but lives in the console database. This keeps the developer identity separate from the end-user identity.

Organizations



Organizations group multiple dev users under shared project ownership. Created within the console by any dev user (who becomes the first admin).

organization
├── members (dev_users with roles)
├── projects
└── billing profiles


Relationship to core.auth



core.console delegates authentication to core.auth entirely. It does not store passwords, manage sessions, or handle 2FA. It consumes the auth layer.

Ownership Model



Projects belong to either a dev user or an organization, never both.

dev_user ──owns──→ project A
dev_user ──owns──→ project B

organization ──owns──→ project C
organization ──owns──→ project D


Project Transfer



Projects can be transferred from a dev user to an organization, but not the reverse. This is a one-way operation.

Transfer flow — transferring user is an org admin:
  1. Dev user selects project → "Transfer to organization"

  2. Picks target org (must be admin of it)

  3. Assigns a billing profile from the org

  4. Transfer completes immediately

  5. Project appears under the org's project list

  6. API keys, stats, logs, config — all unchanged

Transfer flow — transferring user is not an org admin:
  1. Dev user selects project → "Transfer to organization"

  2. Picks target org (must be at least a viewer)

  3. Transfer request created (pending state)

  4. Org admin sees the pending request

  5. Admin approves and assigns a billing profile

  6. Transfer completes

The project is removed from the dev user's project list once transfer completes.

Data Model



Dev Users



CREATE TABLE dev_users (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL UNIQUE, -- FK → core.auth users
username VARCHAR(100) UNIQUE NOT NULL, -- dev username, prefilled from auth
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);


Organizations



CREATE TABLE organizations (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
created_by INT NOT NULL, -- FK → dev_users.id
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);


Organization Members



CREATE TABLE organization_members (
id INT PRIMARY KEY AUTO_INCREMENT,
organization_id INT NOT NULL,
dev_user_id INT NOT NULL,
role ENUM('admin', 'member', 'viewer') DEFAULT 'member',
invited_by INT NOT NULL, -- FK → dev_users.id
invited_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
joined_at TIMESTAMP NULL,
status ENUM('pending', 'active', 'removed') DEFAULT 'pending',
UNIQUE KEY (organization_id, dev_user_id)
);


Roles:
  • Admin — full access. Can manage members, billing, services, projects, settings. Implicit full scopes — no rows needed in org_member_scopes.

  • Member — blocked by default. Admins grant specific permissions per project or org-wide.

  • Viewer — blocked by default. Same as member but intended for read-heavy access patterns.

Organization Member Scopes



Fine-grained permission grants for non-admin members. Admins create allow rules per member, per project or org-wide.

CREATE TABLE org_member_scopes (
id INT PRIMARY KEY AUTO_INCREMENT,
org_member_id INT NOT NULL, -- FK → organization_members.id
project_id INT NULL, -- NULL = org-wide scope
permission ENUM(
'view_stats',
'view_logs',
'view_keys',
'create_keys',
'manage_services',
'manage_billing',
'manage_members',
'manage_settings'
) NOT NULL,
allowed BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY (org_member_id, project_id, permission)
);


Scope resolution:
  1. Is user an admin? → full access, no lookup needed.

  2. Look up org_member_scopes where org_member_id matches and (project_id = X or project_id IS NULL).

  3. Most specific wins (project-level overrides org-wide).

  4. No matching row → denied (default deny for non-admins).

Projects



CREATE TABLE projects (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
slug VARCHAR(100) NOT NULL,
owner_dev_user_id INT NULL, -- FK → dev_users.id
owner_org_id INT NULL, -- FK → organizations.id
enabled_services JSON NOT NULL DEFAULT '[]', -- ["auth","storage","ai","hypermedia"]
status ENUM('active', 'suspended') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT chk_single_owner CHECK (
(owner_dev_user_id IS NOT NULL AND owner_org_id IS NULL) OR
(owner_dev_user_id IS NULL AND owner_org_id IS NOT NULL)
),
UNIQUE KEY (slug, owner_dev_user_id),
UNIQUE KEY (slug, owner_org_id)
);


Kill switch: Setting status = 'suspended' causes the API gateway to reject all requests for that project with a clear error. Used for emergency shutoff.

Pending Project Transfers



Holds transfer requests when a non-admin dev user initiates a project transfer to an org.

CREATE TABLE pending_project_transfers (
id INT PRIMARY KEY AUTO_INCREMENT,
project_id INT NOT NULL, -- FK → projects
from_dev_user_id INT NOT NULL, -- FK → dev_users.id (requester)
to_org_id INT NOT NULL, -- FK → organizations.id
billing_profile_id INT NULL, -- FK → billing_profiles (assigned by admin)
approved_by INT NULL, -- FK → dev_users.id (admin who approved)
status ENUM('pending', 'approved', 'rejected') DEFAULT 'pending',
requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
resolved_at TIMESTAMP NULL
);


API Keys



Each project can have multiple API keys with scoped permissions. Keys are scoped subsets of the project's enabled services.

CREATE TABLE api_keys (
id INT PRIMARY KEY AUTO_INCREMENT,
project_id INT NOT NULL, -- FK → projects
name VARCHAR(255) NOT NULL, -- "Production - Storage Only"
key_hash VARCHAR(255) NOT NULL, -- Argon2id hash of the key
key_prefix VARCHAR(32) NOT NULL, -- first N chars for display (app decides length)
allowed_services JSON NOT NULL DEFAULT '[]', -- subset of project's enabled_services
quotas JSON, -- per-key quota overrides (optional)
expires_at TIMESTAMP NULL,
last_used_at TIMESTAMP NULL,
status ENUM('active', 'revoked') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);


Key display: The raw API key is shown once at creation time. After that, only the key_prefix is visible. The key_hash is stored; the raw key is never persisted.

Project Security Rules



Controls which IPs and domains can make API calls to a project. This is the "where can calls come from" layer — separate from scoping ("what services") and quotas ("how much").

Rules can be set at two levels:
  • Project-wide (service IS NULL) — applies to all services in the project

  • Per-service (service = 'auth'/'storage'/'ai'/'hypermedia') — overrides project-wide rules for that service

CREATE TABLE project_security_rules (
id INT PRIMARY KEY AUTO_INCREMENT,
project_id INT NOT NULL, -- FK → projects
service VARCHAR(50) NULL, -- NULL = project-wide, or 'auth','storage','ai','hypermedia'
rule_type ENUM('ip', 'domain') NOT NULL,
value VARCHAR(255) NOT NULL, -- IP, CIDR, domain, or wildcard domain
description VARCHAR(255), -- "Office VPN", "Production server"
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_project_service (project_id, service)
);


Rule values:
  • IP: 203.0.113.1

  • CIDR: 10.0.0.0/8

  • Domain: app.example.com

  • Wildcard domain: *.example.com

Default: deny all. A project with zero rules is completely locked down — no API calls are accepted. Developers must add at least one security rule before any API key works. This is intentional: security is opt-out (by adding rules), not opt-in.

Resolution at the gateway:
  1. Request arrives for project P, service X

  2. Look for service-specific rules (project_id = P AND service = X)

  3. If found → enforce those rules

  4. If none → fall back to project-wide rules (project_id = P AND service IS NULL)

  5. If no rules at all → deny (deny-by-default)

Example:
Project "My App" security rules:
├── (service=NULL, ip, 10.0.0.0/8) → project-wide: internal network only
├── (service='storage', domain, *.cdn.com) → storage override: allow CDN domains
└── (service='auth', ip, 203.0.113.5) → auth override: single production server


Requests from 10.0.0.5 to storage → allowed (matches project-wide AND service-specific domain rule).
Requests from 203.0.113.5 to auth → allowed (matches service-specific IP rule).
Requests from 8.8.8.8 to ai → denied (matches nothing).

Console UI: The Security page in the project sidebar lets the user toggle between project-wide mode (simple) and per-service mode (granular). An overview shows the current protection status ("X rules active, project-wide + Y service-specific").

Billing Profiles



Billing is attached to the owner (dev user or org), not to individual projects. Each project links to exactly one billing profile.

CREATE TABLE billing_profiles (
id INT PRIMARY KEY AUTO_INCREMENT,
owner_dev_user_id INT NULL, -- FK → dev_users.id
owner_org_id INT NULL, -- FK → organizations.id
name VARCHAR(255) NOT NULL, -- "Default", "Company Card", etc.
plan VARCHAR(50) DEFAULT 'free',
payment_method JSON, -- tokenized payment details
status ENUM('active', 'suspended', 'cancelled') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT chk_single_billing_owner CHECK (
(owner_dev_user_id IS NOT NULL AND owner_org_id IS NULL) OR
(owner_dev_user_id IS NULL AND owner_org_id IS NOT NULL)
)
);

CREATE TABLE project_billing (
id INT PRIMARY KEY AUTO_INCREMENT,
project_id INT NOT NULL UNIQUE, -- FK → projects
billing_profile_id INT NOT NULL, -- FK → billing_profiles
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);


A dev user or org can have multiple billing profiles. When a project is created or transferred, it is assigned to one of the owner's billing profiles.

Request Log



Granular, per-request log. Primarily error-focused — stores enough to debug issues and audit API usage. Written by the API gateway on every request.

CREATE TABLE request_log (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
api_key_id INT NOT NULL,
project_id INT NOT NULL,
service VARCHAR(50) NOT NULL, -- "auth", "storage", "ai", etc.
endpoint VARCHAR(255) NOT NULL,
method VARCHAR(10),
status_code INT,
response_ms INT,
ip_address VARCHAR(45),
user_agent VARCHAR(500),
error_message TEXT NULL, -- only populated on errors
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_project_created (project_id, created_at),
INDEX idx_api_key_created (api_key_id, created_at),
INDEX idx_status (status_code, created_at)
);


Project Stats



Precomputed, aggregated metrics. Written by a periodic aggregation job that reads from request_log. Used for dashboards and graphs — never queried raw from request_log.

CREATE TABLE project_stats (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
project_id INT NOT NULL,
service VARCHAR(50) NOT NULL, -- "auth", "storage", "ai", etc.
period_start TIMESTAMP NOT NULL, -- start of the aggregation window (hourly)
total_requests INT DEFAULT 0,
successful_requests INT DEFAULT 0,
failed_requests INT DEFAULT 0,
avg_response_ms INT DEFAULT 0,
quota_units INT DEFAULT 0,
UNIQUE KEY idx_project_service_period (project_id, service, period_start)
);


An hourly aggregation job runs:
  1. Read request_log entries for the previous hour

  2. Group by project_id + service

  3. Write/update one row per project per service per hour in project_stats

Console stats pages query project_stats, not request_log. The request log page queries request_log directly with filters (status code, time range, service).

Avatars



Polymorphic avatar storage for dev users, organizations, and projects.

CREATE TABLE avatars (
id INT PRIMARY KEY AUTO_INCREMENT,
entity_type ENUM('dev_user', 'organization', 'project') NOT NULL,
entity_id INT NOT NULL,
url VARCHAR(500) NOT NULL,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY idx_entity (entity_type, entity_id)
);


To-Dos



Context-sensitive checklist items for projects, dev users, and organizations. Generated automatically based on entity state, or created by the system (e.g., pending transfer → to-do for org admin).

CREATE TABLE todos (
id INT PRIMARY KEY AUTO_INCREMENT,
entity_type ENUM('project', 'dev_user', 'organization') NOT NULL,
entity_id INT NOT NULL,
title VARCHAR(255) NOT NULL, -- "Add security rules"
description TEXT,
action_url VARCHAR(500), -- link to the relevant page
status ENUM('pending', 'completed', 'dismissed') DEFAULT 'pending',
sort_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP NULL,
INDEX idx_entity_status (entity_type, entity_id, status)
);


Notifications



In-console notifications for org invites, transfer requests, and system alerts.

CREATE TABLE notifications (
id INT PRIMARY KEY AUTO_INCREMENT,
dev_user_id INT NOT NULL, -- FK → dev_users.id (recipient)
type ENUM('org_invite', 'transfer_request', 'transfer_approved', 'transfer_rejected', 'system') NOT NULL,
title VARCHAR(255) NOT NULL,
message TEXT,
action_url VARCHAR(500), -- link to take action
reference_type VARCHAR(50), -- 'organization', 'project', etc.
reference_id INT, -- ID of the referenced entity
status ENUM('unread', 'read', 'dismissed') DEFAULT 'unread',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_dev_user_status (dev_user_id, status)
);


Scoping Model



Three layers of scope, from broadest to narrowest:

1. Project enabled_services    → which services exist on this project
2. API key allowed_services → which services this key can access
3. Quota enforcement → how much this key can use


Org-Level Scopes (console UI permissions)



Separate from API key scoping. Controls what a member can see/do in the console UI:

PermissionAdminMember (default)Viewer (default)









View stats, logs, keys
View full API key value
Create/revoke API keys
Enable/disable services
Manage billing
Manage members
Manage project settings
Transfer projects

Admins can grant any of these to members/viewers via org_member_scopes, per project or org-wide.

Billing Model



Billing lives at the owner level (dev user or org), not at the project level.

dev_user
├── billing profile A ("Personal")
├── billing profile B ("Client X")
└── projects:
├── project 1 → billing A
└── project 2 → billing B

organization
├── billing profile C ("Company Default")
├── billing profile D ("Enterprise")
└── projects:
├── project 3 → billing C
└── project 4 → billing D


On project transfer:
  • Admin transfer: admin picks billing profile from the org during transfer

  • Non-admin transfer: admin picks billing profile when approving the transfer

A project always has exactly one billing profile. Billing profiles can be shared across multiple projects under the same owner.

Stats & Logs Architecture



Stats and logs are separate concepts, separate tables, separate pages in the UI.

Request Log



  • Table: request_log

  • Purpose: Debugging, auditing, error investigation

  • Granularity: One row per API request

  • Retention: Configurable (e.g., 30 days)

  • UI: Filterable log viewer (by status, service, time range, API key)

Project Stats



  • Table: project_stats

  • Purpose: Dashboards, usage graphs, trend analysis

  • Granularity: One row per project per service per hour

  • Retention: Long-term (12+ months)

  • UI: Charts, graphs, period comparisons

Aggregation Job



Every hour:
FOR each (project_id, service) with requests in the last hour:
COMPUTE total, successful, failed, avg_response_ms, quota_units
UPSERT into project_stats WHERE period_start = <last_hour>


Console-Level Pooled Views



At the dev user or org level, stats and billing are pooled across all owned projects:

  • Pooled stats — total requests, per-service breakdown, top projects

  • Pooled billing — current plan, usage against plan limits, invoices

  • Pooled logs — filterable across all projects

Console UI Architecture



Layout



┌──────────────────────────────────────────────────────────────────────┐
│ TOP BAR │
│ [User/Org selector] [Project selector] [Search] [User Circle] │
├──────────┬───────────────────────────────────┬───────────────────────┤
│ │ │ │n│ LEFT │ MAIN AREA │ RIGHT SIDEBAR │
│ NAV │ │ │
│ │ (content changes based on │ ┌───────────────┐ │
│ Changes │ what's open: dev user page, │ │ Notifications │ │
│ based │ org page, or project view) │ │ - org invites │ │
│ on what │ │ │ - transfers │ │
│ is open │ │ │ - alerts │n│ │ │ ├───────────────┤ │
│ │ │ │ To-Dos │ │
│ │ │ │ - project: │ │
│ │ │ │ setup list │ │
│ │ │ │ - user/org: │ │
│ │ │ │ checklists │ │
├──────────┴───────────────────────────────────┴───────────────────────┤
│ FOOTER │
│ [Useful links] [Branding] [Legal] │
└──────────────────────────────────────────────────────────────────────┘


Top bar — always visible:
  • User/Org selector — switch between dev user context and organization contexts

  • Project selector — dropdown of accessible projects for the current owner

  • Search — global search (projects, members, settings)

  • User Circle — owned by core.auth (session context), delivered through core.console (avatar, account, logout)

Left nav — changes based on what's open:
  • Dev user page → dev user navigation

  • Org page → org navigation

  • Project view → project navigation

Main area — content for the selected page

Right sidebar — split into two panels:
  • Notifications — org invites, transfer requests, system alerts

  • To-Dos / Checklists — context-sensitive setup guides for the current project, user, or org

Footer — links, branding, legal

Three Navigation Modes



The left nav and main area change based on what the user has opened.

#### Dev User Page

Dev User: olivmiron
├── Dashboard — overview of all projects, pooled stats
├── My Projects — list of owned projects
├── Organizations — orgs I belong to
├── Billing — billing profiles
├── Notifications — invites, alerts
└── Settings — dev profile, username, avatar


#### Organization Page

Organization: Acme Corp
├── Dashboard — overview of all org projects, pooled stats
├── Projects — list of org projects
├── Members — list, invite, remove, scope management
├── Billing — org billing profiles
├── Pending Transfers — incoming project transfer requests
└── Settings — name, slug, avatar


#### Project View

Project: My App
├── Overview — enabled services, quick stats, project status
├── Stats — usage graphs, per-service breakdown, request volume
├── Logs — granular request log, filterable
├── API Keys — create/revoke keys, view prefixes, manage scopes
├── Security — IP/domain whitelists (project-wide or per-service)
├── Services — enable/disable: auth, ai, storage, hypermedia
├── Billing — assigned billing profile, usage against limits
└── Settings — name, slug, status (kill switch), transfer


Project Creation



Project creation is a short 1–2 page form, not a wizard. The console is the only place for project customization — no separate setup flow.

Creation form:
  1. Owner selection (dev user or one of the user's orgs)

  2. Project name

  3. Slug (auto-generated from name, editable)

  4. Avatar (optional)

After creation, the project opens in the main view with a to-do checklist in the right sidebar guiding the user through finalization:

Project Setup — My App
□ Add security rules (IP/domain whitelist)
□ Enable services (auth, storage, ai, hypermedia)
□ Create an API key
□ Assign billing profile
□ [Per-service setup items, based on enabled services]


The checklist is the single source of truth for "what's left to do". Items disappear as they're completed. The project starts fully functional (status = active) but locked down (no security rules = deny all) until the user configures it.

Per-Service Pages



Each enabled service gets a sub-page under "Services" for configuration. First iteration: enable/disable toggle only. Future iterations add per-service configuration (e.g., auth settings, storage pool management).

Services
├── auth — toggle on/off
├── ai — toggle on/off
├── storage — toggle on/off
└── hypermedia — toggle on/off


To-Do System



To-dos are context-sensitive and appear in the right sidebar:

  • Project to-dos — setup checklist, shown when a project is open

  • Org to-dos — pending transfers, member invites, shown when an org is open

  • User to-dos — onboarding steps, profile completion, shown on the dev user page

To-do items are generated automatically based on the state of the entity (project with no security rules → "Add security rules" item). Items can also be system-generated (pending transfer → "Review transfer request" item for org admins).

Dev User Onboarding



When a core.auth user visits core.console for the first time:

  1. Terms acceptance — must agree to developer terms

  2. Username selection — pre-filled from auth profile, editable

  3. Dev user createddev_users row inserted

  4. Redirected to dashboard — empty project list, onboarding to-dos shown

Organization Invitations



  1. Admin searches for a dev username in the console

  2. Admin sends invitation

  3. Dev user receives email + in-console notification (right sidebar)

  4. Dev user accepts (via email link or console notification)

  5. organization_members.statusactive, joined_at set

Request Flow



Client (core.backend SDK)

│ POST /v1/storage/upload
│ Header: Authorization: Bearer <api_key>


core.console (API Gateway)

├── 1. Resolve project from API key
├── 2. Security check: IP + domain rules (deny-by-default if no rules)
├── 3. Validate API key (hash lookup)
├── 4. Check: project.status = 'active'?
├── 5. Check: is "storage" in this key's allowed_services?
├── 6. Check: has the project exceeded its quota?
├── 7. Log request to request_log

├──→ core.storage (internal request)


Response to client


SSO Integration



core.console is the SSO entry point for the entire platform. It delegates authentication to core.auth but manages the session context:

  1. User visits console.medkronos.com

  2. Redirected to core.auth for login (if no session)

  3. core.auth authenticates, returns to console

  4. Console session created — user can now manage projects, keys, and view usage

  5. API calls from client SDKs use API keys, not user sessions

Service Registration



Each core service registers itself with core.console, declaring:
  • Its name and slug

  • Its available endpoints

  • Its quota model (how usage is counted)

  • Its health check endpoint

This allows core.console to route dynamically and detect service health.

Client SDK (core.backend)



core.backend becomes the client SDK. Applications install it via Composer:

use Unvrsl\Console\Client;

$client = new Client([
'api_key' => 'mk_live_abc123...',
'base_url' => 'https://core.console.medkronos.com/v1'
]);

// Upload a file (routes to core.storage)
$client->storage()->upload('bucket', 'file.pdf', $contents);

// Authenticate a user (routes to core.auth)
$user = $client->auth()->validateToken($token);

// Process media (routes to core.hypermedia)
$result = $client->hypermedia()->convert($fileId, 'pdf');


Storage Pool Provisioning



When a dev user creates a storage pool for a project, core.console orchestrates the provisioning but never touches S3 credentials directly.

Flow



Dev user: "Create Storage Pool" for project P


core.console → GET /api/storage/providers (core.storage)
│ Returns catalog: providers, regions, price tiers (no credentials)


core.console renders selection panel
│ - Lists available providers with regions and pricing
│ - Recommends based on project location (proximity + cost)


Dev user selects provider + region, names the pool


core.console → POST /api/storage/pools (core.storage)
│ Body: { project_id, display_name, provider_ref, region }


core.storage creates the actual S3 bucket, returns pool_id


Pool is ready for uploads


Key principle: core.console is the UI/orchestration layer. core.storage owns the infrastructure — providers, credentials, buckets, and S3 operations. The catalog endpoint exposes provider metadata (names, regions, pricing) but never credentials.

Storage Architecture · Provider Model

Related