Technical Documentation

Complete architecture, formulas, and system reference for startfrom.today

1. Architecture Overview

  • Frontend: React 18 + Vite + TypeScript + Tailwind CSS + shadcn/ui
  • State: TanStack React Query (staleTime 5 min, gcTime 30 min)
  • Backend: own API at api.startfrom.today — Node.js (Fastify), Postgres 16 + Apache AGE (skill graph), MinIO object storage, Caddy; deployed on DigitalOcean
  • AI: Anthropic Claude via the Anthropic API (extraction, classification, matching — no user API key needed)
  • MCP: first-party MCP server at api.startfrom.today/v1/mcp with its own OAuth 2.1 authorization server
  • Visualisation: D3.js (force-directed graph, sunburst), Recharts (bar/radar charts)

2. Database Schema (23 tables)

TablePurposeKey Columns
profilesUser metadata & settingsuser_id, full_name, onboarding_completed, dashboard_layout, public_widgets
user_skillsAggregated skill hoursuser_id, skill_name, hours
user_experiencesWork history entriesuser_id, title, company, start_date, end_date, description
user_educationEducation entriesuser_id, degree, institution, start_date, end_date
experience_skillsSkills linked to experienceexperience_id → user_experiences, skill_name, weight
education_skillsSkills linked to educationeducation_id → user_education, skill_name, weight
user_actionsDaily learning actionsuser_id, description, duration_minutes, action_date
action_skillsSkills linked to actionsaction_id → user_actions, skill_name
user_booksBooks read by useruser_id, title, author, pages, isbn
book_skillsSkills linked to booksbook_id → user_books, skill_name
skill_classificationsAI-assigned category + EQF leveluser_id, skill_name, category, eqf_level
ai_cachePer-user AI response cache (7-day TTL)user_id, cache_type, cache_key, response, expires_at
global_ai_cacheShared AI response cachecache_type, cache_key, response
ai_agentsAI tool directoryname, category, description, url, pricing, active
esco_occupationsESCO occupation taxonomyid, title, isco_code, uri
esco_skillsESCO skill taxonomyid, title, skill_type, uri
esco_occupation_skillsOccupation ↔ skill mappingoccupation_id, skill_id, relation_type
user_connectionsFriendship links (bidirectional)user_id, friend_id, invitation_id
friend_requestsPending friend requestssender_id, receiver_id, status
messagesDirect messages between friendssender_id, receiver_id, content, read
invitationsInvite codesinviter_id, invite_code
user_rolesRBAC rolesuser_id, role (admin | moderator | user)
analytics_eventsPage-view telemetryuser_id, page, event_type, metadata
family_kidsChildren linked to a parent profileuser_id, name, birth_date
kid_education_tracksEducation pathways planned per kidkid_id → family_kids, track_type, label
kid_track_yearsYear-by-year breakdown of a kid's tracktrack_id → kid_education_tracks, year, focus
kid_passportsCitizenships/passports stored per kidkid_id → family_kids, country, number
spouse_linksSpouse relationships between profilesuser_id, spouse_user_id
profile_discoveryDiscoverable public profile indexuser_id, display_name, mastery

3. Skill Hours Calculation

Hours are computed per calendar month for each experience/education entry that overlaps that month.

monthly_hours = 167 / concurrent_entries_that_month

Where 167 = average working hours per month (2000 / 12).

The monthly hours are then distributed across skills by weight:

skill_hours = Σ(monthly_hours × (weight_i / Σweights))

Action hours are added directly: duration_minutes / 60. Books contribute pages × 3 / 60 hours (3 min/page estimate), split equally across book skills.

4. Mapped Percentage

mapped% = Σ min(cell_hours, cell_capacity) / 262,800 × 100

Denominator = 12 fields × 8 depth levels, with per-level capacities of 50 / 150 / 400 / 800 / 1,500 / 3,000 / 6,000 / 10,000 h. Hours above a cell's capacity still count as hours but stop moving the percentage. See the methodology for the reasoning.

5. Depth Level Classification

Each skill is classified into one of 12 domain categories and assigned a depth level (1–8) by the AI classification engine (Gemini model). The classification considers:

  • Skill name and context from linked experiences/education
  • Complexity and specialisation indicators
  • Alignment with the EQF 1–8 depth descriptors used internally
EQFLabelDescription
1BasicGeneral knowledge, simple tasks
2ElementaryBasic factual knowledge, routine work
3IntermediateBroad knowledge, range of cognitive skills
4Upper-IntermediateFactual & theoretical in broad contexts
5AdvancedComprehensive, specialised knowledge
6ProfessionalAdvanced knowledge, critical understanding
7ExpertHighly specialised, research-level
8PioneerMost advanced frontier of a field

6. Earning Potential Model

Salary estimation matches user skills against occupation salary ranges, adjusted by seniority:

adjusted_salary = low + (high - low) × seniority

Where:

  • low, high — salary range from the matched occupation
  • seniority — capped at 1.0, computed from merged experience years + advanced degree bonus:
seniority = min(1, expMultiplier + (hasAdvancedDegree ? 0.1 : 0))

Experience multiplier tiers:

  • ≤ 2 years → 0
  • 2–5 years → 0.3
  • 5–10 years → 0.6
  • > 10 years → 0.85

Top 3 matching occupations are weighted by skill match percentage to produce a blended estimate. Experience intervals are merged to avoid double-counting overlapping roles.

Pareto analysis: Identifies the smallest set of skills that drive 80% of earning potential, weighted by how many top roles each skill matches.

7. Automation Risk Score

risk = Σ(probability_i × hours_i) / Σ(hours_i)

Each skill receives an automation probability (0–1) from the AI engine. The overall risk is a weighted average where skills with more invested hours have proportionally more influence.

8. Skill Graph (D3 Force-Directed)

The interactive skill graph uses D3's force simulation with these parameters:

  • Center force: pulls all nodes toward viewport center
  • Charge force: d3.forceManyBody().strength(-200) — repulsion between nodes
  • Link force: connects skill nodes to their domain category nodes
  • Node radius: proportional to sqrt(hours)
  • Colour mapping: 12 category colours assigned via ordinal scale
  • Recommended nodes: Future-Proof skill recommendations appear as red "Recommended" nodes connected to relevant domain categories

9. Sunburst Chart

Hierarchical ring chart built with d3.partition(). Three levels:

  • Center: total skill hours
  • Inner ring: 12 domain categories (sized by sum of hours)
  • Outer ring: individual skills within each category

10. API & AI Pipelines

FunctionPurposeAI Model
/v1/ai/classify-skillsAssign category + EQF level to skillsClaude
/v1/ai/classify-work-typeClassify skills into work-type quadrantsClaude
/v1/ai/describe-skillGenerate skill descriptions (single & batch)Claude
/v1/ai/recommend-skillsSuggest new skills based on profileClaude
/v1/ai/automation-riskScore automation resistance per skillClaude
/v1/ai/profile-summaryAI-written profile summaryClaude
/v1/ai/parse-cvExtract structured data from uploaded CVsClaude
/v1/ai/extract-action-skillsExtract skills from action descriptionsClaude
/v1/ai/extract-book-skillsExtract skills from book metadataClaude
/v1/ai/analyze-jobMatch a job posting against your recordClaude
/v1/skills · /v1/actions · /v1/booksRecord CRUD + hours recalculation—
/v1/me/* · /v1/profile/*Profile core, experiences, education—
/v1/network · /v1/messages · /v1/family · /v1/streaksSocial contour—
/v1/esco/*Public ESCO taxonomy (occupations, skills)—
/v1/storage/* · /v1/files/*Avatars and CV archive (MinIO)—
/v1/billing/*Stripe checkout, portal, webhooks—
/v1/auth/* · /v1/oauth/*Own auth + OAuth 2.1 AS for MCP—

11. AI Caching Strategy

  • Per-user cache (ai_cache): keyed by cache_type + cache_key, expires after 7 days. Used for user-specific results (recommendations, summaries, work-type classifications).
  • Global cache (global_ai_cache): shared across users. Used for skill descriptions, automation risk scores per skill, and other non-personalised data.
  • Client-side: React Query with staleTime: Infinity for AI-cached data (never refetches within a session) and standard stale times for user data.

12. Dashboard System

The dashboard consists of 19 draggable "plates" whose order is persisted in profiles.dashboard_layout as a JSON array. AI-powered plates display real-time skill counts and previews fetched from cached AI responses.

  • Plates: Skills & Hours, All Human Knowledge (Mastery %), Earning Potential, Pareto Skills, Automation Risk, Skill Graph, Future-Proof Skills, Recommended Skills, Work-Life Balance, Achievements, Books, Invite Friends, High-Value Skills, Diagram, Total Skills, Total Hours, and 4 Work-Type Quadrant plates (Routine/Non-Routine × Intellectual/Physical)
  • Layout is drag-reorderable and saved on drop
  • Each plate can be toggled for public profile visibility via profiles.public_widgets
  • Enriched plates: Automation Risk shows top 3 highest and bottom 3 lowest risk skills; Future-Proof shows avg risk and matching occupations; Earning Potential shows seniority-adjusted estimate with top 3 matched roles; Invite Friends shows side-by-side sphere comparison

13. Authentication & Security

  • Own authentication: Sign in with Apple, Google, and email/password (argon2id hashing)
  • ES256-signed JWT access tokens + refresh-token rotation with reuse detection
  • The database is private — every read and write goes through the API, which enforces per-account access on each request (no client-side database access)
  • Friend-scoped reads (skills, sphere, experiences) require an accepted connection, checked server-side
  • MCP clients authorize through our OAuth 2.1 authorization server (dynamic client registration, mandatory PKCE, user consent page)
  • RBAC via user_roles table (admin-only endpoints)

14. Public Profile Sharing

Users can share a public profile URL. Visible widgets are controlled by the public_widgets JSON column. Public profile data is fetched using service-role RPC to bypass RLS while still respecting the widget visibility settings.

15. Skill Name Formatting & Deduplication

  • Title Case: All skill names are formatted in Title Case across the platform using a shared toTitleCase() utility
  • Deduplication: Case-insensitive deduplication is applied in the Groups view and skill recommendations to prevent duplicate entries
  • Consistency: Formatting is applied at the display layer — stored skill names remain as-is for backward compatibility

16. Invitation & Network System

  • Invite link: https://startfrom.today/invite/:code
  • Default message: "I know (XX)% of all human knowledge, check out yours" — where XX is the user's mastery percentage
  • Friend requests: Acceptance creates bidirectional user_connections entries
  • Network page: Three tabs — Friends (with chat links), Discover (with search), Invite (shareable link + custom message)
  • Direct messaging: Friends can exchange messages via the Messages page with real-time read receipts

17. Strategic Skill Recommendations

  • Future-Proof Skills: Skills absent from user profile, with automation risk <40%, found in occupations matching >15% of existing skills. Dashboard plate previews top 3 lowest-risk skills with average risk score and occupation unlocks. Full list at /dashboard/future-proof-skills
  • You Might Also Know: AI-suggested skills based on co-occurrence, prerequisites & domain patterns. Dashboard plate shows up to 4 example skill names. Full list at /dashboard/recommended-skills
  • Graph integration: Future-Proof recommendations appear as red "Recommended" nodes in the Skill Graph
  • Course generation: The personalised learning course is generated exclusively from Future-Proof skills

18. Knowledge Sphere & Compare

  • Sphere view: Sunburst chart visualising mastery across 12 ESCO categories × 8 ISCED levels (skills from work are levelled with the EQF descriptors)
  • Compare mode: Side-by-side sunburst comparison with connected friends, toggled via Sphere/Compare switch
  • Skills views: List, Graph, and Groups tabs — Groups organise skills exclusively by ESCO category

19. Action Editing

Logged daily actions are fully editable inline. Users can modify any action after creation without needing to delete and re-create it.

  • Duration: Editable numeric input — changes are saved to user_actions.duration_minutes via UPDATE policy
  • Date: Calendar date picker (shadcn) — future dates are disabled. Updates user_actions.action_date
  • Remove skills: Each skill badge shows an × button in edit mode. Removing a skill deletes the action_skills row and subtracts the proportional hours from user_skills
  • Add skills: Inline text input to add new skills. Inserts into action_skills and upserts hours into user_skills
  • Hour redistribution: When skills are added or removed, the action's duration is redistributed proportionally across the updated skill set
  • RLS: UPDATE policy on user_actions ensures only the owner can edit their actions