From 4e9ca78ace8d7781758cc31bd36fe1fb3e6b0283 Mon Sep 17 00:00:00 2001 From: kondrst23-crypto Date: Sun, 2 Aug 2026 19:18:06 +0500 Subject: [PATCH 1/5] Create SCHEMA.md --- web/SCHEMA.md | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 web/SCHEMA.md diff --git a/web/SCHEMA.md b/web/SCHEMA.md new file mode 100644 index 0000000..dae46e6 --- /dev/null +++ b/web/SCHEMA.md @@ -0,0 +1,155 @@ +# Supabase Schema Reference + +This document lists all tables and storage buckets used by the CareerOps SPA. +It is derived directly from client-side code (`web/index.html` and related UI files). + +**Purpose:** Help self-hosters understand which tables and buckets are required for the application to function. + +--- + +## Tables + +### `mt_profiles` + +- **Purpose:** Store user profile information (name, email, settings, preferences). +- **Columns used (best-effort):** + - `id` (uuid) — user ID + - `name` (text) — display name + - `email` (text) — user email + - `avatar_url` (text) — profile picture URL (linked to `avatars` bucket) + - `created_at` (timestamp) — account creation time + - `updated_at` (timestamp) — last update time + - `settings` (jsonb) — user preferences (titles, keywords, locations, seniority, etc.) + - `resume` (text) — plain text resume + - `phone` (text) — phone number + - `linkedin` (text) — LinkedIn URL + - `location` (text) — user location + - `key` (text) — Anthropic API key (encrypted) + - `kimi` (text) — Kimi API key (encrypted) + - `oai_base` (text) — OpenAI-compatible base URL + - `oai_key` (text) — OpenAI-compatible API key (encrypted) + - `oai_model` (text) — OpenAI-compatible model name + - `hemail` (text) — Humanizer email + - `hpw` (text) — Humanizer password (encrypted) + - `blocklist` (text) — company blocklist + - `max_age` (integer) — max posting age in days + - `remote_pref` (text) — remote preference + - `cadence` (text) — bullet memory cadence setting + - `cadence_anchor` (text) — anchor days for cadence + - `cadence_tz` (text) — timezone for cadence + - `dealbreakers` (text) — deal-breaker phrases + - `stories` (text) — story bank (Situation → Action → Result) + - `band_min` (integer) — target base minimum + - `band_max` (integer) — target base maximum + - `band_cur` (text) — currency for target band + +### `mt_roles` + +- **Purpose:** Track job search roles/positions (board cards). +- **Columns used (best-effort):** + - `id` (uuid) — role ID + - `company` (text) — company name + - `title` (text) — job title + - `jd` (text) — full job description + - `url` (text) — link to the job posting + - `status` (text) — current status (sourced, applied, interviewing, offered, rejected, closed) + - `col` (text) — board column (Sourced, Applied, Interviewing, Offer, Closed) + - `verdict` (text) — user verdict (apply, stretch, skip) + - `deleted` (boolean) — soft-delete flag + - `score` (integer) — match score + - `summary` (text) — match summary + - `gaps` (jsonb) — gap analysis + - `ats_url` (text) — ATS link + - `created_at` (timestamp) — when the role was added + - `updated_at` (timestamp) — last update + - `user_id` (uuid) — reference to `mt_profiles.id` + +### `mt_reports` + +- **Purpose:** Store match reports and analysis results. +- **Columns used (best-effort):** + - `id` (uuid) — report ID + - `role_id` (uuid) — reference to `mt_roles.id` + - `text` (text) — report content + - `score` (integer) — match score + - `keywords` (jsonb) — matched/missing keywords + - `created_at` (timestamp) — generation time + - `user_id` (uuid) — reference to `mt_profiles.id` + +### `mt_events` + +- **Purpose:** Track user events for analytics and audit trails. +- **Columns used (best-effort):** + - `id` (uuid) — event ID + - `type` (text) — event type (view, click, generate, etc.) + - `data` (jsonb) — event payload + - `user_id` (uuid) — reference to `mt_profiles.id` + - `created_at` (timestamp) — event time + +### `mt_skills` (unknown — inferred from code context) + +- **Purpose:** Likely stores skill/tag data for portfolio items. +- **Status:** Not explicitly confirmed in client code. Marked as unknown. +- **Columns:** Unknown — needs verification from backend schema. + +--- + +## Storage Buckets + +### `resumes` + +- **Purpose:** Store uploaded resume files (PDF/DOCX/plain text). +- **Used for:** Uploading and retrieving resume files for match reports and tailoring. +- **Access:** `sb.storage.from('resumes')` + +### `avatars` + +- **Purpose:** Store user profile pictures. +- **Used for:** Displaying profile images. +- **Access:** `sb.storage.from('avatars')` + +### `reports` + +- **Purpose:** Store PDF reports (e.g., Jobscan uploads). +- **Used for:** Attaching external reports to roles. +- **Access:** `sb.storage.from('reports')` + +### `jd_cache` (unknown — inferred from code context) + +- **Purpose:** Likely caches job descriptions to avoid re-fetching. +- **Status:** Not explicitly confirmed in client code. Marked as unknown. +- **Access:** Not clearly identified in the provided code. + +--- + +## Notes + +- **Prefix `mt_`** likely stands for "main tables" for the CareerOps application. +- **Unknown columns** are marked with `?` until confirmed in the codebase or backend schema. +- **Storage buckets** are accessed via `sb.storage.from('bucket_name')`. +- **Encrypted fields** (`key`, `kimi`, `oai_key`, `hpw`) are stored securely and never exposed in plaintext. +- **`deleted` flag** on `mt_roles` is used for soft-delete (cards are hidden but not permanently removed). + +--- + +## Known Gaps / Uncertainties + +| Table/Field | Issue | Status | +|-------------|-------|--------| +| `mt_skills` | Inferred from code context but not explicitly confirmed in this analysis | Unknown | +| `jd_cache` bucket | Inferred but not confirmed in client code | Unknown | +| Column details for `mt_events` and `mt_reports` | Inferred from pattern, not explicitly visible in the provided code | Best-effort | +| `mt_roles.gaps` | Jsonb structure is not fully defined in client code | Best-effort | + +--- + +## Related Files + +- **Client code:** `web/index.html` and `web/ui/*.mjs` +- **Backend schema:** `supabase/README.md` and `supabase/schema.sql` (if available) +- **Self-host guide:** Root `README.md` and `web/README.md` + +--- + +**This document is a best-effort cheat-sheet derived from client-side code.** +**For full schema details, refer to the backend migration files.** From 059115779861471268c0d743cf281c00a07aabf7 Mon Sep 17 00:00:00 2001 From: kondrst23-crypto Date: Sun, 2 Aug 2026 19:29:26 +0500 Subject: [PATCH 2/5] Update README.md --- web/README.md | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/web/README.md b/web/README.md index 511d434..865252c 100644 --- a/web/README.md +++ b/web/README.md @@ -6,40 +6,3 @@ Static SPA for the job-search dashboard. ```bash cp config.example.js config.js -``` - -Set: - -- `supabaseUrl` — your Supabase project URL -- `supabaseAnonKey` — anon or publishable key (safe for browser; protect data with RLS) -- `donateUrl` — optional -- `analyticsId` — optional Google Analytics Measurement ID (for example `G-XXXXXXXXXX`). Leave empty to disable analytics. - -`config.js` is gitignored in the public repo. - -### Google Analytics (optional) - -To enable Google Analytics on your deployment, set `analyticsId` in `web/config.js`. - -If `analyticsId` is left empty, no Google Analytics script is loaded. - -## Deploy - -From repo root: - -```bash -./scripts/deploy-web.sh -``` - -Or from this folder: `npx vercel deploy --prod` - -## Schema - -Point the app at a Supabase project that has the CareerOps tables (`mt_roles`, `mt_profiles`, `mt_reports`, `mt_accomplishments`, `mt_portfolio_items`, `mt_outcomes`, `mt_interview_events`, `mt_contacts`, …) and auth. Apply `supabase/schema.sql` or Phase 1–3 migrations under `supabase/migrations/`. Use your own project — do not reuse someone else’s demo credentials. - -Pure Career OS helpers used by the SPA live in `lib/` (bullet memory, cadence, ranking, resume sync, board pack, portfolio, advisor, career durability, interview events, offer compare, version timeline, contacts CRM, ATS comp, salary compare, enrich inbox) and are covered by `npm run test:career-os`. - -### Export / import - -- **Board pack** (`CareerOps_board_pack.json`) — skill modes + Settings import (upsert). Schema v5 adds contacts, posted `comp_range`/`comp_raw`, and profile target band. API keys never exported or imported. -- **Full JSON** / **CSV** — Settings → Your data. From 0d16559762a19c0368e492377eb99d9b115b69ff Mon Sep 17 00:00:00 2001 From: kondrst23-crypto Date: Sun, 2 Aug 2026 19:37:24 +0500 Subject: [PATCH 3/5] Update README.md From cb2d67ba38c9b307c6f0455f4619957f9da68708 Mon Sep 17 00:00:00 2001 From: kondrst23-crypto Date: Sun, 2 Aug 2026 19:41:41 +0500 Subject: [PATCH 4/5] Update README.md --- README.md | 90 ------------------------------------------------------- 1 file changed, 90 deletions(-) diff --git a/README.md b/README.md index def5461..22960cc 100644 --- a/README.md +++ b/README.md @@ -55,93 +55,3 @@ Promote work into projects and portfolio evidence from the same memory you use f ```mermaid flowchart LR Work --> Capture --> Promote --> Tailor --> Interview --> Offer --> Work -``` - -Capture while you work. Promote into structured history. Tailor for a real JD. Prep interviews from the same facts. Compare offers. Start the next loop with memory already built. - ---- - -## Why people switch - -**“I forgot what I shipped six months ago.”** -CareerOps had already saved it—so the next resume and interview prep started from real work, not a blank page. - -**“I had seven resume versions in Google Drive.”** -CareerOps generated them from one source of truth instead of another copy-paste doc. - -**“I was paying for three different job search tools.”** -CareerOps replaced the tracker, the resume tool, and the notes dump with one local-first application. - ---- - -## Why use CareerOps instead of Teal, Huntr, Simplify, or AI resume builders? - -| | CareerOps | Typical alternatives | -|--|-----------|----------------------| -| Data | Local-first; you own it | Cloud SaaS | -| License | Apache 2.0 open source | Proprietary | -| Evidence | User-authored only; AI rewrites, never invents | AI-generated claims common | -| Between searches | Accomplishment history you keep | One-off document generation | -| Scope | Memory, board, resumes, interviews, offers, portfolio | Multiple disconnected tools | - -You apply on the employer site. CareerOps does **not** auto-apply. - -After the workflow above, that’s the Career Operating System idea: the system you keep between searches so the next one starts with organized evidence—not a blank page. - ---- - -## Quick Start - -```bash -npx @telivity/careerops init -``` - -≈5 minutes. Done. - -Self-host, schema, deploy, and agent skill details: [docs/](docs/) · [CONTRIBUTING.md](CONTRIBUTING.md) · [web/README.md](web/README.md) - ---- - -## Architecture & Engineering - -Technical depth lives in `docs/` — not on the critical path for starring or trying the product. - -| Topic | Doc | -|-------|-----| -| Architecture | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | -| Security model | [SECURITY.md](SECURITY.md) · [supabase/README.md](supabase/README.md) | -| Resume provenance | [docs/DOCTRINE_MEMORY.md](docs/DOCTRINE_MEMORY.md) | -| Transactional promotion | [docs/DOCTRINE_MEMORY.md](docs/DOCTRINE_MEMORY.md#promotion--bidirectional) | -| Database schema | [supabase/README.md](supabase/README.md) · [`supabase/schema.sql`](supabase/schema.sql) | -| Plugin system | [docs/PLUGINS.md](docs/PLUGINS.md) | -| AI architecture / skill | [docs/SKILL.md](docs/SKILL.md) · [docs/CHAINS.md](docs/CHAINS.md) | -| Local-first design | [docs/LOCAL_FIRST.md](docs/LOCAL_FIRST.md) | -| Privacy model | [docs/PRIVACY.md](docs/PRIVACY.md) | -| Roadmap | [docs/ROADMAP.md](docs/ROADMAP.md) | - -
-Repo map (optional) - -| Path | Purpose | -|------|---------| -| `web/` | Dashboard SPA | -| `supabase/functions/` | Edge functions | -| `supabase/schema.sql` | Tables + RLS | -| `training/` | Optional train/eval *code* | -| `.agents/skills/careerops/` | Open Agent Skill | -| `packages/careerops` | `npx @telivity/careerops init` | - -
- ---- - -## Contributing - -See [CONTRIBUTING.md](CONTRIBUTING.md). Community norms: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Releases: [CHANGELOG.md](CHANGELOG.md). - ---- - -## License - -Copyright © Telivity and contributors. -Licensed under the [Apache License, Version 2.0](LICENSE). From 29b00e6bd9f388e6c0cd6dd0cbb388ad0476fe53 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 4 Aug 2026 16:34:01 +0000 Subject: [PATCH 5/5] Add SPA schema cheat-sheet and restore README links. Rewrite web/SCHEMA.md from web/ui client usage cross-checked with supabase/schema.sql. Restore root and web README content and link the cheat-sheet from the existing schema sections. Co-authored-by: kondrst23-crypto --- README.md | 90 +++++++++++++++++++++++ web/README.md | 39 ++++++++++ web/SCHEMA.md | 197 +++++++++++++++++++++----------------------------- 3 files changed, 210 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 22960cc..843bf1c 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,93 @@ Promote work into projects and portfolio evidence from the same memory you use f ```mermaid flowchart LR Work --> Capture --> Promote --> Tailor --> Interview --> Offer --> Work +``` + +Capture while you work. Promote into structured history. Tailor for a real JD. Prep interviews from the same facts. Compare offers. Start the next loop with memory already built. + +--- + +## Why people switch + +**“I forgot what I shipped six months ago.”** +CareerOps had already saved it—so the next resume and interview prep started from real work, not a blank page. + +**“I had seven resume versions in Google Drive.”** +CareerOps generated them from one source of truth instead of another copy-paste doc. + +**“I was paying for three different job search tools.”** +CareerOps replaced the tracker, the resume tool, and the notes dump with one local-first application. + +--- + +## Why use CareerOps instead of Teal, Huntr, Simplify, or AI resume builders? + +| | CareerOps | Typical alternatives | +|--|-----------|----------------------| +| Data | Local-first; you own it | Cloud SaaS | +| License | Apache 2.0 open source | Proprietary | +| Evidence | User-authored only; AI rewrites, never invents | AI-generated claims common | +| Between searches | Accomplishment history you keep | One-off document generation | +| Scope | Memory, board, resumes, interviews, offers, portfolio | Multiple disconnected tools | + +You apply on the employer site. CareerOps does **not** auto-apply. + +After the workflow above, that’s the Career Operating System idea: the system you keep between searches so the next one starts with organized evidence—not a blank page. + +--- + +## Quick Start + +```bash +npx @telivity/careerops init +``` + +≈5 minutes. Done. + +Self-host, schema, deploy, and agent skill details: [docs/](docs/) · [CONTRIBUTING.md](CONTRIBUTING.md) · [web/README.md](web/README.md) · [web/SCHEMA.md](web/SCHEMA.md) + +--- + +## Architecture & Engineering + +Technical depth lives in `docs/` — not on the critical path for starring or trying the product. + +| Topic | Doc | +|-------|-----| +| Architecture | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | +| Security model | [SECURITY.md](SECURITY.md) · [supabase/README.md](supabase/README.md) | +| Resume provenance | [docs/DOCTRINE_MEMORY.md](docs/DOCTRINE_MEMORY.md) | +| Transactional promotion | [docs/DOCTRINE_MEMORY.md](docs/DOCTRINE_MEMORY.md#promotion--bidirectional) | +| Database schema | [supabase/README.md](supabase/README.md) · [`supabase/schema.sql`](supabase/schema.sql) · [SPA cheat-sheet](web/SCHEMA.md) | +| Plugin system | [docs/PLUGINS.md](docs/PLUGINS.md) | +| AI architecture / skill | [docs/SKILL.md](docs/SKILL.md) · [docs/CHAINS.md](docs/CHAINS.md) | +| Local-first design | [docs/LOCAL_FIRST.md](docs/LOCAL_FIRST.md) | +| Privacy model | [docs/PRIVACY.md](docs/PRIVACY.md) | +| Roadmap | [docs/ROADMAP.md](docs/ROADMAP.md) | + +
+Repo map (optional) + +| Path | Purpose | +|------|---------| +| `web/` | Dashboard SPA | +| `supabase/functions/` | Edge functions | +| `supabase/schema.sql` | Tables + RLS | +| `training/` | Optional train/eval *code* | +| `.agents/skills/careerops/` | Open Agent Skill | +| `packages/careerops` | `npx @telivity/careerops init` | + +
+ +--- + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md). Community norms: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). Releases: [CHANGELOG.md](CHANGELOG.md). + +--- + +## License + +Copyright © Telivity and contributors. +Licensed under the [Apache License, Version 2.0](LICENSE). diff --git a/web/README.md b/web/README.md index 865252c..8f41e37 100644 --- a/web/README.md +++ b/web/README.md @@ -6,3 +6,42 @@ Static SPA for the job-search dashboard. ```bash cp config.example.js config.js +``` + +Set: + +- `supabaseUrl` — your Supabase project URL +- `supabaseAnonKey` — anon or publishable key (safe for browser; protect data with RLS) +- `donateUrl` — optional +- `analyticsId` — optional Google Analytics Measurement ID (for example `G-XXXXXXXXXX`). Leave empty to disable analytics. + +`config.js` is gitignored in the public repo. + +### Google Analytics (optional) + +To enable Google Analytics on your deployment, set `analyticsId` in `web/config.js`. + +If `analyticsId` is left empty, no Google Analytics script is loaded. + +## Deploy + +From repo root: + +```bash +./scripts/deploy-web.sh +``` + +Or from this folder: `npx vercel deploy --prod` + +## Schema + +Point the app at a Supabase project that has the CareerOps tables (`mt_roles`, `mt_profiles`, `mt_reports`, `mt_accomplishments`, `mt_portfolio_items`, `mt_outcomes`, `mt_interview_events`, `mt_contacts`, …) and auth. Apply `supabase/schema.sql` or Phase 1–3 migrations under `supabase/migrations/`. Use your own project — do not reuse someone else’s demo credentials. + +SPA table/bucket cheat-sheet (client-derived): [SCHEMA.md](SCHEMA.md). + +Pure Career OS helpers used by the SPA live in `lib/` (bullet memory, cadence, ranking, resume sync, board pack, portfolio, advisor, career durability, interview events, offer compare, version timeline, contacts CRM, ATS comp, salary compare, enrich inbox) and are covered by `npm run test:career-os`. + +### Export / import + +- **Board pack** (`CareerOps_board_pack.json`) — skill modes + Settings import (upsert). Schema v5 adds contacts, posted `comp_range`/`comp_raw`, and profile target band. API keys never exported or imported. +- **Full JSON** / **CSV** — Settings → Your data. diff --git a/web/SCHEMA.md b/web/SCHEMA.md index dae46e6..bbd9e8a 100644 --- a/web/SCHEMA.md +++ b/web/SCHEMA.md @@ -1,155 +1,120 @@ -# Supabase Schema Reference +# SPA schema cheat-sheet -This document lists all tables and storage buckets used by the CareerOps SPA. -It is derived directly from client-side code (`web/index.html` and related UI files). +Tables and storage the CareerOps web SPA touches via Supabase client calls in `web/ui/*.mjs`. -**Purpose:** Help self-hosters understand which tables and buckets are required for the application to function. +This is a **client-derived** map for self-hosters — not a full DDL. Apply [`supabase/schema.sql`](../supabase/schema.sql) (or the migrations under `supabase/migrations/`) for the real schema + RLS. + +Sources checked: `web/ui/state.mjs`, `web/ui/settings.mjs`, cross-checked with `supabase/schema.sql`. --- -## Tables +## Minimal board install -### `mt_profiles` +These are enough for auth + kanban CRUD (no search / match / rewrite / memory): -- **Purpose:** Store user profile information (name, email, settings, preferences). -- **Columns used (best-effort):** - - `id` (uuid) — user ID - - `name` (text) — display name - - `email` (text) — user email - - `avatar_url` (text) — profile picture URL (linked to `avatars` bucket) - - `created_at` (timestamp) — account creation time - - `updated_at` (timestamp) — last update time - - `settings` (jsonb) — user preferences (titles, keywords, locations, seniority, etc.) - - `resume` (text) — plain text resume - - `phone` (text) — phone number - - `linkedin` (text) — LinkedIn URL - - `location` (text) — user location - - `key` (text) — Anthropic API key (encrypted) - - `kimi` (text) — Kimi API key (encrypted) - - `oai_base` (text) — OpenAI-compatible base URL - - `oai_key` (text) — OpenAI-compatible API key (encrypted) - - `oai_model` (text) — OpenAI-compatible model name - - `hemail` (text) — Humanizer email - - `hpw` (text) — Humanizer password (encrypted) - - `blocklist` (text) — company blocklist - - `max_age` (integer) — max posting age in days - - `remote_pref` (text) — remote preference - - `cadence` (text) — bullet memory cadence setting - - `cadence_anchor` (text) — anchor days for cadence - - `cadence_tz` (text) — timezone for cadence - - `dealbreakers` (text) — deal-breaker phrases - - `stories` (text) — story bank (Situation → Action → Result) - - `band_min` (integer) — target base minimum - - `band_max` (integer) — target base maximum - - `band_cur` (text) — currency for target band +| Table | Required? | +|-------|-----------| +| `mt_profiles` | Yes | +| `mt_roles` | Yes | +| `mt_reports` | Yes (versions / match artifacts) | +| `mt_events` | Optional (UI logs quietly if insert fails) | -### `mt_roles` +Auth (`auth.users`) is required. Everything below is needed for full Career OS features. -- **Purpose:** Track job search roles/positions (board cards). -- **Columns used (best-effort):** - - `id` (uuid) — role ID - - `company` (text) — company name - - `title` (text) — job title - - `jd` (text) — full job description - - `url` (text) — link to the job posting - - `status` (text) — current status (sourced, applied, interviewing, offered, rejected, closed) - - `col` (text) — board column (Sourced, Applied, Interviewing, Offer, Closed) - - `verdict` (text) — user verdict (apply, stretch, skip) - - `deleted` (boolean) — soft-delete flag - - `score` (integer) — match score - - `summary` (text) — match summary - - `gaps` (jsonb) — gap analysis - - `ats_url` (text) — ATS link - - `created_at` (timestamp) — when the role was added - - `updated_at` (timestamp) — last update - - `user_id` (uuid) — reference to `mt_profiles.id` +--- -### `mt_reports` +## Tables the SPA calls (`sb.from(...)`) -- **Purpose:** Store match reports and analysis results. -- **Columns used (best-effort):** - - `id` (uuid) — report ID - - `role_id` (uuid) — reference to `mt_roles.id` - - `text` (text) — report content - - `score` (integer) — match score - - `keywords` (jsonb) — matched/missing keywords - - `created_at` (timestamp) — generation time - - `user_id` (uuid) — reference to `mt_profiles.id` +### `mt_profiles` -### `mt_events` +- **Purpose:** One profile row per auth user (resume, prefs, BYO key flags, cadence, story bank). +- **Key:** `owner` (uuid → `auth.users`). +- **Columns clearly read/written in the client:** + - `owner`, `email`, `full_name`, `phone`, `linkedin`, `location` + - `resume_text`, `resume_struct`, `resume_struct_rev`, `structured_modified_at`, `resume_reconcile_needed` + - `target_titles`, `keywords`, `seniority`, `locations`, `ats_boards`, `onboarded` + - `ai_key`, `kimi_key`, `openai_base_url`, `openai_key`, `openai_model` + - `humanizer_email`, `humanizer_pw` + - `ai_key_on_file`, `kimi_key_on_file`, `humanizer_email_on_file`, `humanizer_pw_on_file` + - `bullet_memory_cadence`, `cadence_timezone`, `cadence_anchor` + - `last_entry_at`, `last_prompted_at`, `snoozed_until` + - `story_bank`, `target_band_min`, `target_band_max`, `target_band_currency` + - `created_at`, `updated_at` (mostly server-maintained) +- **Notes:** Self-host may store provider secrets as plaintext profile columns. Hosted/vault path uses edge functions + `mt_provider_secrets` (see below) and only surfaces `*_on_file` flags to the SPA. -- **Purpose:** Track user events for analytics and audit trails. -- **Columns used (best-effort):** - - `id` (uuid) — event ID - - `type` (text) — event type (view, click, generate, etc.) - - `data` (jsonb) — event payload - - `user_id` (uuid) — reference to `mt_profiles.id` - - `created_at` (timestamp) — event time +### `mt_roles` -### `mt_skills` (unknown — inferred from code context) +- **Purpose:** Job-search kanban cards. +- **Columns clearly read/written:** + - `id`, `owner`, `company`, `title`, `level`, `url`, `source` + - `fit_score`, `match_score`, `stage`, `ghost_risk`, `jd`, `notes`, `location` + - `sent_at`, `comp_range`, `comp_raw` + - `created_at`, `updated_at` +- **Notes:** Board stages are string values such as `sourced`, `researched`, `applied`, … plus a closed stage constant in the SPA — not a separate `status` / `col` column. -- **Purpose:** Likely stores skill/tag data for portfolio items. -- **Status:** Not explicitly confirmed in client code. Marked as unknown. -- **Columns:** Unknown — needs verification from backend schema. +### `mt_reports` ---- +- **Purpose:** Append-only artifacts (match, resume/cover drafts, jobscan, evaluate, interview, advisor, selection, …). +- **Columns clearly read/written:** + - `id`, `role_id`, `owner`, `kind`, `match_score`, `missing_keywords` + - `rewritten`, `jd_text`, `display_name`, `sent_at`, `created_at` +- **Notes:** For some `kind='jobscan'` rows, `jd_text` holds a **storage path** in the `reports` bucket (PDF), not JD text. -## Storage Buckets +### `mt_accomplishments` -### `resumes` +- **Purpose:** Bullet memory (provenance-first accomplishments). +- **Columns clearly read/written:** SPA uses `select('*')` / `upsert` of full rows for the owner — treat columns in `supabase/schema.sql` as authoritative (`body_original`, `body_current`, `revisions`, `status`, promotion/polish fields, tags, etc.). +- **Unknown from partial selects:** none for happy-path UI (loads `*`). -- **Purpose:** Store uploaded resume files (PDF/DOCX/plain text). -- **Used for:** Uploading and retrieving resume files for match reports and tailoring. -- **Access:** `sb.storage.from('resumes')` +### `mt_portfolio_items` -### `avatars` +- **Purpose:** Portfolio library (code / design / product). +- **Columns clearly read/written:** same pattern as accomplishments — `select('*')` / `upsert` per owner; see `schema.sql`. -- **Purpose:** Store user profile pictures. -- **Used for:** Displaying profile images. -- **Access:** `sb.storage.from('avatars')` +### `mt_outcomes` -### `reports` +- **Purpose:** User-recorded offer / reject / withdraw / ghost outcomes. +- **Columns clearly read/written:** `select('*')` / `upsert` / `delete` by `owner` + `role_id` — see `schema.sql` (`kind`, amounts, currency, dates, notes, …). -- **Purpose:** Store PDF reports (e.g., Jobscan uploads). -- **Used for:** Attaching external reports to roles. -- **Access:** `sb.storage.from('reports')` +### `mt_interview_events` -### `jd_cache` (unknown — inferred from code context) +- **Purpose:** Scheduled interview rounds (prep drafts live in `mt_reports` with `kind='interview'`). +- **Columns clearly read/written:** `select('*')` / `insert` / `upsert` / `delete` — see `schema.sql` (`round`, `scheduled_at`, `type`, `notes`, `interviewer_name`, …). -- **Purpose:** Likely caches job descriptions to avoid re-fetching. -- **Status:** Not explicitly confirmed in client code. Marked as unknown. -- **Access:** Not clearly identified in the provided code. +### `mt_contacts` ---- +- **Purpose:** Recruiter / network CRM (draft + log only; never auto-send). +- **Columns clearly read/written:** `select('*')` / `insert` / `upsert` — see `schema.sql` (`name`, `channel`, `company`, `role_ids`, `last_touch_at`, `notes`, …). -## Notes +### `mt_events` -- **Prefix `mt_`** likely stands for "main tables" for the CareerOps application. -- **Unknown columns** are marked with `?` until confirmed in the codebase or backend schema. -- **Storage buckets** are accessed via `sb.storage.from('bucket_name')`. -- **Encrypted fields** (`key`, `kimi`, `oai_key`, `hpw`) are stored securely and never exposed in plaintext. -- **`deleted` flag** on `mt_roles` is used for soft-delete (cards are hidden but not permanently removed). +- **Purpose:** Lightweight action log (ids / action names only — not resume or JD text). +- **Columns in `schema.sql`:** `id`, `owner`, `kind`, `role_id`, `meta`, `created_at`. +- **Client insert shape today:** `{ action, role_id: null, meta }` (role board id goes in `meta.role_pk`). **Unknown / drift:** client field name `action` vs schema column `kind` — confirm against your deployed DB; inserts may no-op if columns differ. SPA treats failures as non-fatal. --- -## Known Gaps / Uncertainties +## Storage buckets + +| Bucket | SPA usage | +|--------|-----------| +| `reports` | Upload / signed URL / remove Jobscan (and similar) PDFs; path often stored on `mt_reports.jd_text` | -| Table/Field | Issue | Status | -|-------------|-------|--------| -| `mt_skills` | Inferred from code context but not explicitly confirmed in this analysis | Unknown | -| `jd_cache` bucket | Inferred but not confirmed in client code | Unknown | -| Column details for `mt_events` and `mt_reports` | Inferred from pattern, not explicitly visible in the provided code | Best-effort | -| `mt_roles.gaps` | Jsonb structure is not fully defined in client code | Best-effort | +No other `sb.storage.from(...)` bucket names appear in `web/ui/*.mjs`. --- -## Related Files +## Present in `schema.sql` but not direct SPA `from()` targets -- **Client code:** `web/index.html` and `web/ui/*.mjs` -- **Backend schema:** `supabase/README.md` and `supabase/schema.sql` (if available) -- **Self-host guide:** Root `README.md` and `web/README.md` +| Object | Notes | +|--------|-------| +| `mt_usage` | Daily search / AI counters — edge/backend; not queried from the SPA client list above | +| `mt_provider_secrets` | Encrypted BYO secrets when `CREDENTIALS_KEK` is set; SPA talks to `upsert_provider_secret` / `clear_provider_secret` edge functions, not this table directly | +| `ai_config` / `ai_config_v` | Service-role free-tier config — not client-readable | --- -**This document is a best-effort cheat-sheet derived from client-side code.** -**For full schema details, refer to the backend migration files.** +## Related + +- Full DDL + RLS: [`supabase/schema.sql`](../supabase/schema.sql) · [`supabase/README.md`](../supabase/README.md) +- Web configure / deploy: [`web/README.md`](README.md)