API Reference

Hierarch runs a small set of edge functions on Supabase using the Hono framework (Deno runtime). These handle operations that require admin-level database access or server-side processing. All other data operations go directly through the Supabase client library from the browser.

Base URL

https://[project-ref].supabase.co/functions/v1/server

All edge function endpoints are prefixed with /functions/v1/server. The Hono router handles path matching within that base.

Authentication

Protected endpoints require a Supabase access token in the Authorization header:

Authorization: Bearer [supabase_access_token]

The edge function validates the token using supabaseAdmin.auth.getUser(token). Invalid or missing tokens return a 401 Unauthorized response.

Endpoints

POST /signup

Creates a new user account via the Supabase admin API. This endpoint is unauthenticated.

POST /functions/v1/server/signup
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "securepassword"
}

Response: 200
{
  "user": { "id": "uuid", "email": "user@example.com" }
}

POST /upload-avatar

Uploads a user avatar to the Supabase Storage avatars bucket. Returns a signed URL for the uploaded file. Requires authentication.

POST /functions/v1/server/upload-avatar
Authorization: Bearer [token]
Content-Type: multipart/form-data

Form data:
  file: [binary image data]

Response: 200
{
  "url": "https://[project-ref].supabase.co/storage/v1/object/sign/avatars/[path]"
}

GET /time-entries

Lists all focus timer entries for the authenticated user. Entries are stored in the Supabase KV store (separate from Postgres).

GET /functions/v1/server/time-entries
Authorization: Bearer [token]

Response: 200
[
  {
    "id": "entry-uuid",
    "taskId": "task-uuid",
    "duration": 1500,
    "startedAt": "2026-03-16T10:00:00Z",
    "completedAt": "2026-03-16T10:25:00Z"
  }
]

POST /time-entries

Creates a new focus timer entry.

POST /functions/v1/server/time-entries
Authorization: Bearer [token]
Content-Type: application/json

{
  "taskId": "task-uuid",
  "duration": 1500,
  "startedAt": "2026-03-16T10:00:00Z",
  "completedAt": "2026-03-16T10:25:00Z"
}

Response: 200
{ "id": "entry-uuid", ... }

DELETE /time-entries

Deletes a time entry by ID (passed as a query parameter).

DELETE /functions/v1/server/time-entries?id=entry-uuid
Authorization: Bearer [token]

Response: 200
{ "success": true }

DELETE /delete-account

Permanently deletes the authenticated user's account and all associated data (KV entries, stored files, database records).

DELETE /functions/v1/server/delete-account
Authorization: Bearer [token]

Response: 200
{ "success": true }

KV Store

Time entries use Supabase's KV store rather than Postgres. Each entry is keyed as a tuple: ["time_entry", user_id, entry_id]. The edge function provides helper methods for KV operations:

kvSet(key, value)Store a value at the given key tuple
kvGet(key)Retrieve a value by key tuple
kvList(prefix)List all entries matching a key prefix
kvDelete(key)Delete an entry by key tuple

Client Data Layer

Most data operations bypass edge functions entirely and use the Supabase JavaScript client directly from the browser. The data access layer lives at src/app/api/data.ts and provides these core functions:

Projects

getProjects()Fetch all projects for the current user, ordered by created_at
createProject(name, metadata, startDate?, endDate?, description?)Create a new project
updateProject(id, updates)Update project fields (name, description, metadata, dates)
deleteProject(id)Delete a project and cascade to tasks and resources

Tasks

getTasks(projectId?)Fetch tasks. null = unassigned only, undefined = all tasks
createTask(task, projectId?)Create a task with serialized description JSON
updateTask(id, updates)Merge updates into existing task (re-serializes description)
deleteTask(id)Delete a task (linked resources get task_id set to null)

Resources

getResources()Fetch all resources for the current user
createResource(resource)Create a resource with serialized content JSON
updateResource(id, updates)Update resource fields
deleteResource(id)Delete a resource

Data Serialization

Tasks pack multiple fields into the description column as JSON:

{
  "content": "Rich text content (string)",
  "phaseHistory": [
    {
      "id": "string",
      "fromPhase": "string",
      "toPhase": "string",
      "timestamp": "ISO 8601",
      "reviewer": "string (optional)",
      "notes": "string (optional)"
    }
  ]
}

The parseTaskDescription(raw) function unpacks this JSON when reading from the database, and createTask / updateTask re-serialize it when writing.

Error Handling

Edge function errors return standard HTTP status codes:

401Missing or invalid authentication token
400Malformed request body or missing required fields
404Requested resource not found
500Internal server error (database or KV store failure)

Error responses include a JSON body with a message field describing the issue.