--
-- PostgreSQL database dump
--

\restrict TG2nhZgrjloKh7jlMVecLEprHw1a3hDg39djzWHnwuHlz0BazsrNAbub3aaOiFX

-- Dumped from database version 18.0 (Debian 18.0-1.pgdg13+3)
-- Dumped by pg_dump version 18.0 (Debian 18.0-1.pgdg13+3)

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET transaction_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: directus_access; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_access (
    id uuid NOT NULL,
    role uuid,
    "user" uuid,
    policy uuid NOT NULL,
    sort integer
);


ALTER TABLE public.directus_access OWNER TO homelab;

--
-- Name: directus_activity; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_activity (
    id integer NOT NULL,
    action character varying(45) NOT NULL,
    "user" uuid,
    "timestamp" timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    ip character varying(50),
    user_agent text,
    collection character varying(64) NOT NULL,
    item character varying(255) NOT NULL,
    origin character varying(255)
);


ALTER TABLE public.directus_activity OWNER TO homelab;

--
-- Name: directus_activity_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_activity_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_activity_id_seq OWNER TO homelab;

--
-- Name: directus_activity_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_activity_id_seq OWNED BY public.directus_activity.id;


--
-- Name: directus_collections; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_collections (
    collection character varying(64) NOT NULL,
    icon character varying(64),
    note text,
    display_template character varying(255),
    hidden boolean DEFAULT false NOT NULL,
    singleton boolean DEFAULT false NOT NULL,
    translations json,
    archive_field character varying(64),
    archive_app_filter boolean DEFAULT true NOT NULL,
    archive_value character varying(255),
    unarchive_value character varying(255),
    sort_field character varying(64),
    accountability character varying(255) DEFAULT 'all'::character varying,
    color character varying(255),
    item_duplication_fields json,
    sort integer,
    "group" character varying(64),
    collapse character varying(255) DEFAULT 'open'::character varying NOT NULL,
    preview_url character varying(255),
    versioning boolean DEFAULT false NOT NULL
);


ALTER TABLE public.directus_collections OWNER TO homelab;

--
-- Name: directus_comments; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_comments (
    id uuid NOT NULL,
    collection character varying(64) NOT NULL,
    item character varying(255) NOT NULL,
    comment text NOT NULL,
    date_created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    date_updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    user_created uuid,
    user_updated uuid
);


ALTER TABLE public.directus_comments OWNER TO homelab;

--
-- Name: directus_dashboards; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_dashboards (
    id uuid NOT NULL,
    name character varying(255) NOT NULL,
    icon character varying(64) DEFAULT 'dashboard'::character varying NOT NULL,
    note text,
    date_created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    user_created uuid,
    color character varying(255)
);


ALTER TABLE public.directus_dashboards OWNER TO homelab;

--
-- Name: directus_extensions; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_extensions (
    enabled boolean DEFAULT true NOT NULL,
    id uuid NOT NULL,
    folder character varying(255) NOT NULL,
    source character varying(255) NOT NULL,
    bundle uuid
);


ALTER TABLE public.directus_extensions OWNER TO homelab;

--
-- Name: directus_fields; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_fields (
    id integer NOT NULL,
    collection character varying(64) NOT NULL,
    field character varying(64) NOT NULL,
    special character varying(64),
    interface character varying(64),
    options json,
    display character varying(64),
    display_options json,
    readonly boolean DEFAULT false NOT NULL,
    hidden boolean DEFAULT false NOT NULL,
    sort integer,
    width character varying(30) DEFAULT 'full'::character varying,
    translations json,
    note text,
    conditions json,
    required boolean DEFAULT false,
    "group" character varying(64),
    validation json,
    validation_message text
);


ALTER TABLE public.directus_fields OWNER TO homelab;

--
-- Name: directus_fields_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_fields_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_fields_id_seq OWNER TO homelab;

--
-- Name: directus_fields_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_fields_id_seq OWNED BY public.directus_fields.id;


--
-- Name: directus_files; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_files (
    id uuid NOT NULL,
    storage character varying(255) NOT NULL,
    filename_disk character varying(255),
    filename_download character varying(255) NOT NULL,
    title character varying(255),
    type character varying(255),
    folder uuid,
    uploaded_by uuid,
    created_on timestamp with time zone DEFAULT CURRENT_TIMESTAMP CONSTRAINT directus_files_uploaded_on_not_null NOT NULL,
    modified_by uuid,
    modified_on timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    charset character varying(50),
    filesize bigint,
    width integer,
    height integer,
    duration integer,
    embed character varying(200),
    description text,
    location text,
    tags text,
    metadata json,
    focal_point_x integer,
    focal_point_y integer,
    tus_id character varying(64),
    tus_data json,
    uploaded_on timestamp with time zone
);


ALTER TABLE public.directus_files OWNER TO homelab;

--
-- Name: directus_flows; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_flows (
    id uuid NOT NULL,
    name character varying(255) NOT NULL,
    icon character varying(64),
    color character varying(255),
    description text,
    status character varying(255) DEFAULT 'active'::character varying NOT NULL,
    trigger character varying(255),
    accountability character varying(255) DEFAULT 'all'::character varying,
    options json,
    operation uuid,
    date_created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    user_created uuid
);


ALTER TABLE public.directus_flows OWNER TO homelab;

--
-- Name: directus_folders; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_folders (
    id uuid NOT NULL,
    name character varying(255) NOT NULL,
    parent uuid
);


ALTER TABLE public.directus_folders OWNER TO homelab;

--
-- Name: directus_migrations; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_migrations (
    version character varying(255) NOT NULL,
    name character varying(255) NOT NULL,
    "timestamp" timestamp with time zone DEFAULT CURRENT_TIMESTAMP
);


ALTER TABLE public.directus_migrations OWNER TO homelab;

--
-- Name: directus_notifications; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_notifications (
    id integer NOT NULL,
    "timestamp" timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    status character varying(255) DEFAULT 'inbox'::character varying,
    recipient uuid NOT NULL,
    sender uuid,
    subject character varying(255) NOT NULL,
    message text,
    collection character varying(64),
    item character varying(255)
);


ALTER TABLE public.directus_notifications OWNER TO homelab;

--
-- Name: directus_notifications_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_notifications_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_notifications_id_seq OWNER TO homelab;

--
-- Name: directus_notifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_notifications_id_seq OWNED BY public.directus_notifications.id;


--
-- Name: directus_operations; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_operations (
    id uuid NOT NULL,
    name character varying(255),
    key character varying(255) NOT NULL,
    type character varying(255) NOT NULL,
    position_x integer NOT NULL,
    position_y integer NOT NULL,
    options json,
    resolve uuid,
    reject uuid,
    flow uuid NOT NULL,
    date_created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    user_created uuid
);


ALTER TABLE public.directus_operations OWNER TO homelab;

--
-- Name: directus_panels; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_panels (
    id uuid NOT NULL,
    dashboard uuid NOT NULL,
    name character varying(255),
    icon character varying(64) DEFAULT NULL::character varying,
    color character varying(10),
    show_header boolean DEFAULT false NOT NULL,
    note text,
    type character varying(255) NOT NULL,
    position_x integer NOT NULL,
    position_y integer NOT NULL,
    width integer NOT NULL,
    height integer NOT NULL,
    options json,
    date_created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    user_created uuid
);


ALTER TABLE public.directus_panels OWNER TO homelab;

--
-- Name: directus_permissions; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_permissions (
    id integer NOT NULL,
    collection character varying(64) NOT NULL,
    action character varying(10) NOT NULL,
    permissions json,
    validation json,
    presets json,
    fields text,
    policy uuid NOT NULL
);


ALTER TABLE public.directus_permissions OWNER TO homelab;

--
-- Name: directus_permissions_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_permissions_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_permissions_id_seq OWNER TO homelab;

--
-- Name: directus_permissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_permissions_id_seq OWNED BY public.directus_permissions.id;


--
-- Name: directus_policies; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_policies (
    id uuid NOT NULL,
    name character varying(100) NOT NULL,
    icon character varying(64) DEFAULT 'badge'::character varying NOT NULL,
    description text,
    ip_access text,
    enforce_tfa boolean DEFAULT false NOT NULL,
    admin_access boolean DEFAULT false NOT NULL,
    app_access boolean DEFAULT false NOT NULL
);


ALTER TABLE public.directus_policies OWNER TO homelab;

--
-- Name: directus_presets; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_presets (
    id integer NOT NULL,
    bookmark character varying(255),
    "user" uuid,
    role uuid,
    collection character varying(64),
    search character varying(100),
    layout character varying(100) DEFAULT 'tabular'::character varying,
    layout_query json,
    layout_options json,
    refresh_interval integer,
    filter json,
    icon character varying(64) DEFAULT 'bookmark'::character varying,
    color character varying(255)
);


ALTER TABLE public.directus_presets OWNER TO homelab;

--
-- Name: directus_presets_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_presets_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_presets_id_seq OWNER TO homelab;

--
-- Name: directus_presets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_presets_id_seq OWNED BY public.directus_presets.id;


--
-- Name: directus_relations; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_relations (
    id integer NOT NULL,
    many_collection character varying(64) NOT NULL,
    many_field character varying(64) NOT NULL,
    one_collection character varying(64),
    one_field character varying(64),
    one_collection_field character varying(64),
    one_allowed_collections text,
    junction_field character varying(64),
    sort_field character varying(64),
    one_deselect_action character varying(255) DEFAULT 'nullify'::character varying NOT NULL
);


ALTER TABLE public.directus_relations OWNER TO homelab;

--
-- Name: directus_relations_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_relations_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_relations_id_seq OWNER TO homelab;

--
-- Name: directus_relations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_relations_id_seq OWNED BY public.directus_relations.id;


--
-- Name: directus_revisions; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_revisions (
    id integer NOT NULL,
    activity integer NOT NULL,
    collection character varying(64) NOT NULL,
    item character varying(255) NOT NULL,
    data json,
    delta json,
    parent integer,
    version uuid
);


ALTER TABLE public.directus_revisions OWNER TO homelab;

--
-- Name: directus_revisions_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_revisions_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_revisions_id_seq OWNER TO homelab;

--
-- Name: directus_revisions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_revisions_id_seq OWNED BY public.directus_revisions.id;


--
-- Name: directus_roles; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_roles (
    id uuid NOT NULL,
    name character varying(100) NOT NULL,
    icon character varying(64) DEFAULT 'supervised_user_circle'::character varying NOT NULL,
    description text,
    parent uuid
);


ALTER TABLE public.directus_roles OWNER TO homelab;

--
-- Name: directus_sessions; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_sessions (
    token character varying(64) NOT NULL,
    "user" uuid,
    expires timestamp with time zone NOT NULL,
    ip character varying(255),
    user_agent text,
    share uuid,
    origin character varying(255),
    next_token character varying(64)
);


ALTER TABLE public.directus_sessions OWNER TO homelab;

--
-- Name: directus_settings; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_settings (
    id integer NOT NULL,
    project_name character varying(100) DEFAULT 'Directus'::character varying NOT NULL,
    project_url character varying(255),
    project_color character varying(255) DEFAULT '#6644FF'::character varying NOT NULL,
    project_logo uuid,
    public_foreground uuid,
    public_background uuid,
    public_note text,
    auth_login_attempts integer DEFAULT 25,
    auth_password_policy character varying(100),
    storage_asset_transform character varying(7) DEFAULT 'all'::character varying,
    storage_asset_presets json,
    custom_css text,
    storage_default_folder uuid,
    basemaps json,
    mapbox_key character varying(255),
    module_bar json,
    project_descriptor character varying(100),
    default_language character varying(255) DEFAULT 'en-US'::character varying NOT NULL,
    custom_aspect_ratios json,
    public_favicon uuid,
    default_appearance character varying(255) DEFAULT 'auto'::character varying NOT NULL,
    default_theme_light character varying(255),
    theme_light_overrides json,
    default_theme_dark character varying(255),
    theme_dark_overrides json,
    report_error_url character varying(255),
    report_bug_url character varying(255),
    report_feature_url character varying(255),
    public_registration boolean DEFAULT false NOT NULL,
    public_registration_verify_email boolean DEFAULT true NOT NULL,
    public_registration_role uuid,
    public_registration_email_filter json,
    visual_editor_urls json,
    accepted_terms boolean DEFAULT false,
    project_id uuid,
    mcp_enabled boolean DEFAULT false NOT NULL,
    mcp_allow_deletes boolean DEFAULT false NOT NULL,
    mcp_prompts_collection character varying(255) DEFAULT NULL::character varying,
    mcp_system_prompt_enabled boolean DEFAULT true NOT NULL,
    mcp_system_prompt text
);


ALTER TABLE public.directus_settings OWNER TO homelab;

--
-- Name: directus_settings_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_settings_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_settings_id_seq OWNER TO homelab;

--
-- Name: directus_settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_settings_id_seq OWNED BY public.directus_settings.id;


--
-- Name: directus_shares; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_shares (
    id uuid NOT NULL,
    name character varying(255),
    collection character varying(64) NOT NULL,
    item character varying(255) NOT NULL,
    role uuid,
    password character varying(255),
    user_created uuid,
    date_created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    date_start timestamp with time zone,
    date_end timestamp with time zone,
    times_used integer DEFAULT 0,
    max_uses integer
);


ALTER TABLE public.directus_shares OWNER TO homelab;

--
-- Name: directus_translations; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_translations (
    id uuid NOT NULL,
    language character varying(255) NOT NULL,
    key character varying(255) NOT NULL,
    value text NOT NULL
);


ALTER TABLE public.directus_translations OWNER TO homelab;

--
-- Name: directus_users; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_users (
    id uuid NOT NULL,
    first_name character varying(50),
    last_name character varying(50),
    email character varying(128),
    password character varying(255),
    location character varying(255),
    title character varying(50),
    description text,
    tags json,
    avatar uuid,
    language character varying(255) DEFAULT NULL::character varying,
    tfa_secret character varying(255),
    status character varying(16) DEFAULT 'active'::character varying NOT NULL,
    role uuid,
    token character varying(255),
    last_access timestamp with time zone,
    last_page character varying(255),
    provider character varying(128) DEFAULT 'default'::character varying NOT NULL,
    external_identifier character varying(255),
    auth_data json,
    email_notifications boolean DEFAULT true,
    appearance character varying(255),
    theme_dark character varying(255),
    theme_light character varying(255),
    theme_light_overrides json,
    theme_dark_overrides json,
    text_direction character varying(255) DEFAULT 'auto'::character varying NOT NULL
);


ALTER TABLE public.directus_users OWNER TO homelab;

--
-- Name: directus_versions; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_versions (
    id uuid NOT NULL,
    key character varying(64) NOT NULL,
    name character varying(255),
    collection character varying(64) NOT NULL,
    item character varying(255) NOT NULL,
    hash character varying(255),
    date_created timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    date_updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
    user_created uuid,
    user_updated uuid,
    delta json
);


ALTER TABLE public.directus_versions OWNER TO homelab;

--
-- Name: directus_webhooks; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.directus_webhooks (
    id integer NOT NULL,
    name character varying(255) NOT NULL,
    method character varying(10) DEFAULT 'POST'::character varying NOT NULL,
    url character varying(255) NOT NULL,
    status character varying(10) DEFAULT 'active'::character varying NOT NULL,
    data boolean DEFAULT true NOT NULL,
    actions character varying(100) NOT NULL,
    collections character varying(255) NOT NULL,
    headers json,
    was_active_before_deprecation boolean DEFAULT false NOT NULL,
    migrated_flow uuid
);


ALTER TABLE public.directus_webhooks OWNER TO homelab;

--
-- Name: directus_webhooks_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.directus_webhooks_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.directus_webhooks_id_seq OWNER TO homelab;

--
-- Name: directus_webhooks_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.directus_webhooks_id_seq OWNED BY public.directus_webhooks.id;


--
-- Name: posts; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.posts (
    id integer NOT NULL,
    date_created timestamp with time zone,
    date_updated timestamp with time zone,
    title character varying(255),
    published boolean DEFAULT false,
    content text
);


ALTER TABLE public.posts OWNER TO homelab;

--
-- Name: posts_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.posts_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.posts_id_seq OWNER TO homelab;

--
-- Name: posts_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.posts_id_seq OWNED BY public.posts.id;


--
-- Name: profile; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.profile (
    id integer NOT NULL,
    full_name character varying(255),
    first_name character varying(255),
    last_name character varying(255),
    title character varying(255),
    description text,
    email character varying(255),
    location character varying(255),
    portfolio_year character varying(255),
    availability boolean,
    availability_text character varying(255),
    current_role_title character varying(255),
    current_role_company character varying(255),
    current_role_duration character varying(255),
    work_section_title character varying(255),
    work_section_date_range character varying(255),
    connect_title character varying(255),
    connect_description text,
    footer_copyright character varying(255),
    footer_attribution character varying(255),
    footer_year character varying(255)
);


ALTER TABLE public.profile OWNER TO homelab;

--
-- Name: profile_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.profile_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.profile_id_seq OWNER TO homelab;

--
-- Name: profile_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.profile_id_seq OWNED BY public.profile.id;


--
-- Name: skills; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.skills (
    id integer NOT NULL,
    name character varying(255),
    category character varying(255),
    proficiency character varying(255),
    "order" integer,
    featured boolean DEFAULT true
);


ALTER TABLE public.skills OWNER TO homelab;

--
-- Name: skills_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.skills_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.skills_id_seq OWNER TO homelab;

--
-- Name: skills_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.skills_id_seq OWNED BY public.skills.id;


--
-- Name: social_links; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.social_links (
    id integer NOT NULL,
    name character varying(255),
    handle character varying(255),
    url character varying(255),
    icon character varying(255),
    "order" integer,
    visible boolean DEFAULT true
);


ALTER TABLE public.social_links OWNER TO homelab;

--
-- Name: social_links_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.social_links_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.social_links_id_seq OWNER TO homelab;

--
-- Name: social_links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.social_links_id_seq OWNED BY public.social_links.id;


--
-- Name: work_projects; Type: TABLE; Schema: public; Owner: homelab
--

CREATE TABLE public.work_projects (
    id integer NOT NULL,
    status character varying(255) DEFAULT 'draft'::character varying,
    title character varying(255),
    slug character varying(255),
    company character varying(255),
    role character varying(255),
    year character varying(255),
    duration character varying(255),
    description text,
    content text,
    technologies json,
    featured boolean DEFAULT false,
    "order" integer,
    team character varying(255),
    live_url character varying(255),
    case_study_url character varying(255),
    category character varying(255) DEFAULT 'hackathon'::character varying
);


ALTER TABLE public.work_projects OWNER TO homelab;

--
-- Name: work_projects_id_seq; Type: SEQUENCE; Schema: public; Owner: homelab
--

CREATE SEQUENCE public.work_projects_id_seq
    AS integer
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE public.work_projects_id_seq OWNER TO homelab;

--
-- Name: work_projects_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: homelab
--

ALTER SEQUENCE public.work_projects_id_seq OWNED BY public.work_projects.id;


--
-- Name: directus_activity id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_activity ALTER COLUMN id SET DEFAULT nextval('public.directus_activity_id_seq'::regclass);


--
-- Name: directus_fields id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_fields ALTER COLUMN id SET DEFAULT nextval('public.directus_fields_id_seq'::regclass);


--
-- Name: directus_notifications id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_notifications ALTER COLUMN id SET DEFAULT nextval('public.directus_notifications_id_seq'::regclass);


--
-- Name: directus_permissions id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_permissions ALTER COLUMN id SET DEFAULT nextval('public.directus_permissions_id_seq'::regclass);


--
-- Name: directus_presets id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_presets ALTER COLUMN id SET DEFAULT nextval('public.directus_presets_id_seq'::regclass);


--
-- Name: directus_relations id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_relations ALTER COLUMN id SET DEFAULT nextval('public.directus_relations_id_seq'::regclass);


--
-- Name: directus_revisions id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_revisions ALTER COLUMN id SET DEFAULT nextval('public.directus_revisions_id_seq'::regclass);


--
-- Name: directus_settings id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings ALTER COLUMN id SET DEFAULT nextval('public.directus_settings_id_seq'::regclass);


--
-- Name: directus_webhooks id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_webhooks ALTER COLUMN id SET DEFAULT nextval('public.directus_webhooks_id_seq'::regclass);


--
-- Name: posts id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.posts ALTER COLUMN id SET DEFAULT nextval('public.posts_id_seq'::regclass);


--
-- Name: profile id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.profile ALTER COLUMN id SET DEFAULT nextval('public.profile_id_seq'::regclass);


--
-- Name: skills id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.skills ALTER COLUMN id SET DEFAULT nextval('public.skills_id_seq'::regclass);


--
-- Name: social_links id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.social_links ALTER COLUMN id SET DEFAULT nextval('public.social_links_id_seq'::regclass);


--
-- Name: work_projects id; Type: DEFAULT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.work_projects ALTER COLUMN id SET DEFAULT nextval('public.work_projects_id_seq'::regclass);


--
-- Data for Name: directus_access; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_access (id, role, "user", policy, sort) FROM stdin;
ddfe37e3-9f7a-4d51-9f4a-e7d8aa63f30a	\N	\N	abf8a154-5b1c-4a46-ac9c-7300570f4f17	1
b36ef94e-10aa-466a-8c7a-679b6f8b746e	dd3993a4-6217-4159-a014-9fae656d0032	\N	211b930e-e270-4b77-aa7d-283b3aa255e4	\N
\.


--
-- Data for Name: directus_activity; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_activity (id, action, "user", "timestamp", ip, user_agent, collection, item, origin) FROM stdin;
1	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 01:00:29.836+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	http://directus.homelab.local
2	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 01:00:32.445+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_settings	1	http://directus.homelab.local
3	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:24:50.7+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	1	http://directus.homelab.local
4	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:24:50.703+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	2	http://directus.homelab.local
5	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:24:50.705+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	3	http://directus.homelab.local
6	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:24:50.707+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_collections	posts	http://directus.homelab.local
7	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:25:20.28+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	4	http://directus.homelab.local
8	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:25:43.09+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	5	http://directus.homelab.local
9	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:26:14.78+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	6	http://directus.homelab.local
10	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:28:53.638+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_permissions	1	http://directus.homelab.local
11	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:28:53.643+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_policies	abf8a154-5b1c-4a46-ac9c-7300570f4f17	http://directus.homelab.local
12	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:29:54.413+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	1	http://directus.homelab.local
13	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:30:05.439+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	1	http://directus.homelab.local
14	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:30:38.911+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	2	http://directus.homelab.local
15	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:31:04.702+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	3	http://directus.homelab.local
16	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:31:07.86+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	3	http://directus.homelab.local
17	delete	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:35:22.534+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	1	http://directus.homelab.local
18	delete	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:35:22.535+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	2	http://directus.homelab.local
19	delete	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:35:22.536+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	3	http://directus.homelab.local
20	delete	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:35:47.075+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	5	http://directus.homelab.local
21	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:36:32.059+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_fields	7	http://directus.homelab.local
22	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:37:25.554+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	4	http://directus.homelab.local
23	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:37:51.749+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	5	http://directus.homelab.local
24	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 02:38:14.612+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	6	http://directus.homelab.local
25	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:21:19.821+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
26	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.539+00	172.18.1.1	curl/7.88.1	directus_fields	8	\N
27	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.541+00	172.18.1.1	curl/7.88.1	directus_collections	profile	\N
28	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.585+00	172.18.1.1	curl/7.88.1	directus_fields	9	\N
29	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.639+00	172.18.1.1	curl/7.88.1	directus_fields	10	\N
30	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.676+00	172.18.1.1	curl/7.88.1	directus_fields	11	\N
31	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.712+00	172.18.1.1	curl/7.88.1	directus_fields	12	\N
32	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.744+00	172.18.1.1	curl/7.88.1	directus_fields	13	\N
33	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.78+00	172.18.1.1	curl/7.88.1	directus_fields	14	\N
34	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.831+00	172.18.1.1	curl/7.88.1	directus_fields	15	\N
35	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.864+00	172.18.1.1	curl/7.88.1	directus_fields	16	\N
36	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.896+00	172.18.1.1	curl/7.88.1	directus_fields	17	\N
37	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.93+00	172.18.1.1	curl/7.88.1	directus_fields	18	\N
38	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.962+00	172.18.1.1	curl/7.88.1	directus_fields	19	\N
39	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:03.994+00	172.18.1.1	curl/7.88.1	directus_fields	20	\N
40	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.029+00	172.18.1.1	curl/7.88.1	directus_fields	21	\N
41	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.065+00	172.18.1.1	curl/7.88.1	directus_fields	22	\N
42	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.096+00	172.18.1.1	curl/7.88.1	directus_fields	23	\N
43	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.132+00	172.18.1.1	curl/7.88.1	directus_fields	24	\N
44	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.166+00	172.18.1.1	curl/7.88.1	directus_fields	25	\N
45	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.199+00	172.18.1.1	curl/7.88.1	directus_fields	26	\N
46	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.233+00	172.18.1.1	curl/7.88.1	directus_fields	27	\N
47	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:04.269+00	172.18.1.1	curl/7.88.1	directus_fields	28	\N
48	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.765+00	172.18.1.1	curl/7.88.1	directus_fields	29	\N
49	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.768+00	172.18.1.1	curl/7.88.1	directus_collections	work_projects	\N
50	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.803+00	172.18.1.1	curl/7.88.1	directus_fields	30	\N
51	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.842+00	172.18.1.1	curl/7.88.1	directus_fields	31	\N
52	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.885+00	172.18.1.1	curl/7.88.1	directus_fields	32	\N
53	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.917+00	172.18.1.1	curl/7.88.1	directus_fields	33	\N
54	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.948+00	172.18.1.1	curl/7.88.1	directus_fields	34	\N
55	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:54.984+00	172.18.1.1	curl/7.88.1	directus_fields	35	\N
56	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.032+00	172.18.1.1	curl/7.88.1	directus_fields	36	\N
57	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.067+00	172.18.1.1	curl/7.88.1	directus_fields	37	\N
58	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.105+00	172.18.1.1	curl/7.88.1	directus_fields	38	\N
59	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.138+00	172.18.1.1	curl/7.88.1	directus_fields	39	\N
60	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.172+00	172.18.1.1	curl/7.88.1	directus_fields	40	\N
61	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.213+00	172.18.1.1	curl/7.88.1	directus_fields	41	\N
62	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.246+00	172.18.1.1	curl/7.88.1	directus_fields	42	\N
63	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.284+00	172.18.1.1	curl/7.88.1	directus_fields	43	\N
64	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:22:55.325+00	172.18.1.1	curl/7.88.1	directus_fields	44	\N
65	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.167+00	172.18.1.1	curl/7.88.1	directus_fields	45	\N
66	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.171+00	172.18.1.1	curl/7.88.1	directus_collections	skills	\N
67	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.201+00	172.18.1.1	curl/7.88.1	directus_fields	46	\N
68	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.24+00	172.18.1.1	curl/7.88.1	directus_fields	47	\N
69	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.278+00	172.18.1.1	curl/7.88.1	directus_fields	48	\N
70	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.311+00	172.18.1.1	curl/7.88.1	directus_fields	49	\N
71	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.344+00	172.18.1.1	curl/7.88.1	directus_fields	50	\N
72	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.377+00	172.18.1.1	curl/7.88.1	directus_fields	51	\N
73	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.38+00	172.18.1.1	curl/7.88.1	directus_collections	social_links	\N
74	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.41+00	172.18.1.1	curl/7.88.1	directus_fields	52	\N
75	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.445+00	172.18.1.1	curl/7.88.1	directus_fields	53	\N
76	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.475+00	172.18.1.1	curl/7.88.1	directus_fields	54	\N
77	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.506+00	172.18.1.1	curl/7.88.1	directus_fields	55	\N
78	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.539+00	172.18.1.1	curl/7.88.1	directus_fields	56	\N
79	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:23:33.574+00	172.18.1.1	curl/7.88.1	directus_fields	57	\N
80	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:24:25.019+00	172.18.1.1	curl/7.88.1	profile	1	\N
81	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.411+00	172.18.1.1	curl/7.88.1	work_projects	1	\N
82	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.432+00	172.18.1.1	curl/7.88.1	work_projects	2	\N
83	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.452+00	172.18.1.1	curl/7.88.1	work_projects	3	\N
84	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.47+00	172.18.1.1	curl/7.88.1	work_projects	4	\N
85	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.49+00	172.18.1.1	curl/7.88.1	work_projects	5	\N
86	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.512+00	172.18.1.1	curl/7.88.1	work_projects	6	\N
87	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.532+00	172.18.1.1	curl/7.88.1	work_projects	7	\N
88	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:25:42.549+00	172.18.1.1	curl/7.88.1	work_projects	8	\N
89	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:30.929+00	172.18.1.1	curl/7.88.1	skills	1	\N
90	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:30.95+00	172.18.1.1	curl/7.88.1	skills	2	\N
91	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:30.966+00	172.18.1.1	curl/7.88.1	skills	3	\N
92	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:30.983+00	172.18.1.1	curl/7.88.1	skills	4	\N
93	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31+00	172.18.1.1	curl/7.88.1	skills	5	\N
94	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.018+00	172.18.1.1	curl/7.88.1	skills	6	\N
95	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.043+00	172.18.1.1	curl/7.88.1	skills	7	\N
96	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.063+00	172.18.1.1	curl/7.88.1	skills	8	\N
97	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.084+00	172.18.1.1	curl/7.88.1	skills	9	\N
98	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.1+00	172.18.1.1	curl/7.88.1	skills	10	\N
99	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.121+00	172.18.1.1	curl/7.88.1	skills	11	\N
100	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.143+00	172.18.1.1	curl/7.88.1	skills	12	\N
101	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.165+00	172.18.1.1	curl/7.88.1	skills	13	\N
102	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.184+00	172.18.1.1	curl/7.88.1	skills	14	\N
103	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.206+00	172.18.1.1	curl/7.88.1	skills	15	\N
104	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.224+00	172.18.1.1	curl/7.88.1	skills	16	\N
105	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.254+00	172.18.1.1	curl/7.88.1	skills	17	\N
106	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.269+00	172.18.1.1	curl/7.88.1	skills	18	\N
107	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.289+00	172.18.1.1	curl/7.88.1	skills	19	\N
108	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.304+00	172.18.1.1	curl/7.88.1	skills	20	\N
109	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.328+00	172.18.1.1	curl/7.88.1	skills	21	\N
110	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.345+00	172.18.1.1	curl/7.88.1	social_links	1	\N
111	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.364+00	172.18.1.1	curl/7.88.1	social_links	2	\N
112	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:26:31.381+00	172.18.1.1	curl/7.88.1	social_links	3	\N
113	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:30:43.342+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
114	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:35:29.043+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_permissions	2	http://directus.homelab.local
115	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:35:29.046+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_permissions	3	http://directus.homelab.local
116	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:35:29.048+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_permissions	4	http://directus.homelab.local
117	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:35:29.05+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_permissions	5	http://directus.homelab.local
118	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:35:29.052+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	directus_policies	abf8a154-5b1c-4a46-ac9c-7300570f4f17	http://directus.homelab.local
119	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:37:38.993+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
120	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:38:33.95+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
121	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:38:34.417+00	172.18.1.1	curl/7.88.1	work_projects	7	\N
122	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:38:34.438+00	172.18.1.1	curl/7.88.1	work_projects	8	\N
123	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:55.961+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
124	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.433+00	172.18.1.1	curl/7.88.1	directus_fields	58	\N
125	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.486+00	172.18.1.1	curl/7.88.1	work_projects	1	\N
126	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.502+00	172.18.1.1	curl/7.88.1	work_projects	2	\N
127	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.517+00	172.18.1.1	curl/7.88.1	work_projects	3	\N
128	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.533+00	172.18.1.1	curl/7.88.1	work_projects	4	\N
129	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.549+00	172.18.1.1	curl/7.88.1	work_projects	5	\N
130	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.569+00	172.18.1.1	curl/7.88.1	work_projects	6	\N
131	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.586+00	172.18.1.1	curl/7.88.1	work_projects	7	\N
132	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:50:56.605+00	172.18.1.1	curl/7.88.1	work_projects	8	\N
133	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:58:55.165+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
134	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:58:55.63+00	172.18.1.1	curl/7.88.1	work_projects	2	\N
135	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:58:55.646+00	172.18.1.1	curl/7.88.1	work_projects	3	\N
136	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 04:58:55.663+00	172.18.1.1	curl/7.88.1	work_projects	5	\N
137	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:02:07.277+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
138	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:02:07.74+00	172.18.1.1	curl/7.88.1	work_projects	1	\N
139	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:02:07.757+00	172.18.1.1	curl/7.88.1	work_projects	2	\N
140	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:02:07.773+00	172.18.1.1	curl/7.88.1	work_projects	4	\N
141	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:02:07.788+00	172.18.1.1	curl/7.88.1	work_projects	8	\N
142	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:05:55.437+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
143	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:05:55.906+00	172.18.1.1	curl/7.88.1	work_projects	2	\N
144	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:07:15.403+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
145	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:07:15.873+00	172.18.1.1	curl/7.88.1	work_projects	6	\N
146	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:11:02.108+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
147	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:11:02.577+00	172.18.1.1	curl/7.88.1	work_projects	2	\N
148	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:11:02.603+00	172.18.1.1	curl/7.88.1	work_projects	8	\N
149	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:11:02.626+00	172.18.1.1	curl/7.88.1	work_projects	5	\N
150	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:11:02.655+00	172.18.1.1	curl/7.88.1	work_projects	6	\N
151	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:15:04.047+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
152	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:15:32.405+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
153	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:15:32.878+00	172.18.1.1	curl/7.88.1	profile	1	\N
154	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:17:18.75+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
155	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:17:36.835+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
156	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:17:37.328+00	172.18.1.1	curl/7.88.1	posts	7	\N
157	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:55:37.057+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
158	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:57:34.883+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	profile	1	http://directus.homelab.local
159	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:58:28.451+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	skills	13	http://directus.homelab.local
160	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:59:10.553+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	skills	2	http://directus.homelab.local
161	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:59:21.75+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	skills	6	http://directus.homelab.local
162	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:59:34.801+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	skills	18	http://directus.homelab.local
163	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 05:59:52.378+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	skills	2	http://directus.homelab.local
164	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:01:43.704+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
165	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:03:09.53+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
166	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:22:41.956+00	172.18.1.1	Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/141.0.0.0 Safari/537.36	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	http://directus.homelab.local
167	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:26:58.103+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
168	create	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:27:10.442+00	172.18.1.1	curl/7.88.1	posts	8	\N
169	delete	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:28:17.08+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	5	http://directus.homelab.local
170	delete	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:28:17.082+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	6	http://directus.homelab.local
171	delete	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:28:17.083+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	4	http://directus.homelab.local
172	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:29:27.665+00	172.18.1.1	curl/7.88.1	posts	8	\N
173	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:30:22.53+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	8	http://directus.homelab.local
174	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:36:53.31+00	172.18.1.1	curl/7.88.1	posts	8	\N
175	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:37:39.277+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	8	http://directus.homelab.local
176	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:41:33.772+00	172.18.1.1	curl/7.88.1	posts	8	\N
177	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:41:43.716+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	8	http://directus.homelab.local
178	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:48:12.277+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
179	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:48:12.895+00	172.18.1.1	curl/7.88.1	posts	8	\N
180	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:48:20.339+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	8	http://directus.homelab.local
181	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:50:03.298+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	8	http://directus.homelab.local
182	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:50:48.65+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	8	http://directus.homelab.local
183	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:56:49.187+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
184	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:57:03.204+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
185	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:57:15.523+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
186	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:58:50.05+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
187	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:58:50.653+00	172.18.1.1	curl/7.88.1	posts	7	\N
188	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:59:36.598+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
189	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 06:59:52.573+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
190	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:02:18.096+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
191	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:03:25.828+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
192	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:07:43.45+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	work_projects	2	http://directus.homelab.local
193	login	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:23:27.657+00	172.18.1.1	curl/7.88.1	directus_users	446b0591-88bd-4122-8877-6ff5b00e4201	\N
194	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:23:28.298+00	172.18.1.1	curl/7.88.1	posts	7	\N
195	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:25:06.496+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
196	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:25:26.477+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
197	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:26:17.964+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
198	update	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:26:45.09+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	posts	7	http://directus.homelab.local
\.


--
-- Data for Name: directus_collections; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_collections (collection, icon, note, display_template, hidden, singleton, translations, archive_field, archive_app_filter, archive_value, unarchive_value, sort_field, accountability, color, item_duplication_fields, sort, "group", collapse, preview_url, versioning) FROM stdin;
posts	\N	\N	\N	f	f	\N	\N	t	\N	\N	\N	all	\N	\N	\N	\N	open	\N	f
profile	person	Personal and professional information	\N	f	t	\N	\N	t	\N	\N	\N	all	\N	\N	\N	\N	open	\N	f
work_projects	work	Portfolio work experience and projects	\N	f	f	\N	\N	t	\N	\N	order	all	\N	\N	\N	\N	open	\N	f
skills	build	Technical skills and technologies	\N	f	f	\N	\N	t	\N	\N	order	all	\N	\N	\N	\N	open	\N	f
social_links	link	Social media and contact links	\N	f	f	\N	\N	t	\N	\N	order	all	\N	\N	\N	\N	open	\N	f
\.


--
-- Data for Name: directus_comments; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_comments (id, collection, item, comment, date_created, date_updated, user_created, user_updated) FROM stdin;
\.


--
-- Data for Name: directus_dashboards; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_dashboards (id, name, icon, note, date_created, user_created, color) FROM stdin;
\.


--
-- Data for Name: directus_extensions; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_extensions (enabled, id, folder, source, bundle) FROM stdin;
\.


--
-- Data for Name: directus_fields; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_fields (id, collection, field, special, interface, options, display, display_options, readonly, hidden, sort, width, translations, note, conditions, required, "group", validation, validation_message) FROM stdin;
1	posts	id	\N	input	\N	\N	\N	t	t	1	full	\N	\N	\N	f	\N	\N	\N
2	posts	date_created	date-created	datetime	\N	datetime	{"relative":true}	t	t	2	half	\N	\N	\N	f	\N	\N	\N
3	posts	date_updated	date-updated	datetime	\N	datetime	{"relative":true}	t	t	3	half	\N	\N	\N	f	\N	\N	\N
4	posts	title	\N	input	\N	\N	\N	f	f	4	full	\N	\N	\N	t	\N	\N	\N
6	posts	published	cast-boolean	boolean	\N	\N	\N	f	f	6	full	\N	\N	\N	f	\N	\N	\N
7	posts	content	\N	input-code	{"language":"markdown"}	\N	\N	f	f	7	full	\N	\N	\N	f	\N	\N	\N
8	profile	id	\N	numeric	\N	\N	\N	t	t	1	full	\N	\N	\N	f	\N	\N	\N
9	profile	full_name	\N	input	{"placeholder":"Full Name"}	\N	\N	f	f	2	full	\N	\N	\N	t	\N	\N	\N
10	profile	first_name	\N	input	\N	\N	\N	f	f	3	full	\N	\N	\N	t	\N	\N	\N
11	profile	last_name	\N	input	\N	\N	\N	f	f	4	full	\N	\N	\N	t	\N	\N	\N
12	profile	title	\N	input	{"placeholder":"Full Stack Developer"}	\N	\N	f	f	5	full	\N	\N	\N	t	\N	\N	\N
13	profile	description	\N	input-multiline	\N	\N	\N	f	f	6	full	\N	\N	\N	t	\N	\N	\N
14	profile	email	\N	input	{"placeholder":"email@example.com"}	\N	\N	f	f	7	full	\N	\N	\N	t	\N	\N	\N
15	profile	location	\N	input	\N	\N	\N	f	f	8	full	\N	\N	\N	f	\N	\N	\N
16	profile	portfolio_year	\N	input	\N	\N	\N	f	f	9	full	\N	\N	\N	f	\N	\N	\N
17	profile	availability	\N	boolean	\N	\N	\N	f	f	10	full	\N	\N	\N	f	\N	\N	\N
18	profile	availability_text	\N	input	\N	\N	\N	f	f	11	full	\N	\N	\N	f	\N	\N	\N
19	profile	current_role_title	\N	input	\N	\N	\N	f	f	12	full	\N	\N	\N	f	\N	\N	\N
20	profile	current_role_company	\N	input	\N	\N	\N	f	f	13	full	\N	\N	\N	f	\N	\N	\N
21	profile	current_role_duration	\N	input	\N	\N	\N	f	f	14	full	\N	\N	\N	f	\N	\N	\N
22	profile	work_section_title	\N	input	\N	\N	\N	f	f	15	full	\N	\N	\N	f	\N	\N	\N
23	profile	work_section_date_range	\N	input	\N	\N	\N	f	f	16	full	\N	\N	\N	f	\N	\N	\N
24	profile	connect_title	\N	input	\N	\N	\N	f	f	17	full	\N	\N	\N	f	\N	\N	\N
25	profile	connect_description	\N	input-multiline	\N	\N	\N	f	f	18	full	\N	\N	\N	f	\N	\N	\N
26	profile	footer_copyright	\N	input	\N	\N	\N	f	f	19	full	\N	\N	\N	f	\N	\N	\N
27	profile	footer_attribution	\N	input	\N	\N	\N	f	f	20	full	\N	\N	\N	f	\N	\N	\N
28	profile	footer_year	\N	input	\N	\N	\N	f	f	21	full	\N	\N	\N	f	\N	\N	\N
29	work_projects	id	\N	numeric	\N	\N	\N	t	t	1	full	\N	\N	\N	f	\N	\N	\N
30	work_projects	status	\N	select-dropdown	{"choices":[{"text":"Draft","value":"draft"},{"text":"Published","value":"published"},{"text":"Archived","value":"archived"}]}	\N	\N	f	f	2	full	\N	\N	\N	t	\N	\N	\N
31	work_projects	title	\N	input	\N	\N	\N	f	f	3	full	\N	\N	\N	t	\N	\N	\N
32	work_projects	slug	\N	input	{"slug":true}	\N	\N	f	f	4	full	\N	\N	\N	t	\N	\N	\N
33	work_projects	company	\N	input	\N	\N	\N	f	f	5	full	\N	\N	\N	t	\N	\N	\N
34	work_projects	role	\N	input	\N	\N	\N	f	f	6	full	\N	\N	\N	t	\N	\N	\N
35	work_projects	year	\N	input	\N	\N	\N	f	f	7	full	\N	\N	\N	t	\N	\N	\N
36	work_projects	duration	\N	input	\N	\N	\N	f	f	8	full	\N	\N	\N	f	\N	\N	\N
37	work_projects	description	\N	input-multiline	\N	\N	\N	f	f	9	full	\N	\N	\N	t	\N	\N	\N
38	work_projects	content	\N	input-rich-text-md	\N	\N	\N	f	f	10	full	\N	\N	\N	f	\N	\N	\N
39	work_projects	technologies	\N	tags	\N	\N	\N	f	f	11	full	\N	\N	\N	t	\N	\N	\N
40	work_projects	featured	\N	boolean	\N	\N	\N	f	f	12	full	\N	\N	\N	f	\N	\N	\N
41	work_projects	order	\N	input	\N	\N	\N	f	f	13	full	\N	\N	\N	f	\N	\N	\N
42	work_projects	team	\N	input	\N	\N	\N	f	f	14	full	\N	\N	\N	f	\N	\N	\N
43	work_projects	live_url	\N	input	{"placeholder":"https://example.com"}	\N	\N	f	f	15	full	\N	\N	\N	f	\N	\N	\N
44	work_projects	case_study_url	\N	input	\N	\N	\N	f	f	16	full	\N	\N	\N	f	\N	\N	\N
45	skills	id	\N	numeric	\N	\N	\N	t	t	1	full	\N	\N	\N	f	\N	\N	\N
46	skills	name	\N	input	\N	\N	\N	f	f	2	full	\N	\N	\N	t	\N	\N	\N
47	skills	category	\N	select-dropdown	{"choices":[{"text":"Frontend","value":"frontend"},{"text":"Backend","value":"backend"},{"text":"DevOps","value":"devops"},{"text":"AI/ML","value":"aiml"},{"text":"Design","value":"design"}]}	\N	\N	f	f	3	full	\N	\N	\N	f	\N	\N	\N
48	skills	proficiency	\N	select-dropdown	{"choices":[{"text":"Beginner","value":"beginner"},{"text":"Intermediate","value":"intermediate"},{"text":"Expert","value":"expert"}]}	\N	\N	f	f	4	full	\N	\N	\N	f	\N	\N	\N
49	skills	order	\N	input	\N	\N	\N	f	f	5	full	\N	\N	\N	f	\N	\N	\N
50	skills	featured	\N	boolean	\N	\N	\N	f	f	6	full	\N	\N	\N	f	\N	\N	\N
51	social_links	id	\N	numeric	\N	\N	\N	t	t	1	full	\N	\N	\N	f	\N	\N	\N
52	social_links	name	\N	input	\N	\N	\N	f	f	2	full	\N	\N	\N	t	\N	\N	\N
53	social_links	handle	\N	input	\N	\N	\N	f	f	3	full	\N	\N	\N	t	\N	\N	\N
54	social_links	url	\N	input	\N	\N	\N	f	f	4	full	\N	\N	\N	t	\N	\N	\N
55	social_links	icon	\N	select-dropdown	{"choices":[{"text":"GitHub","value":"github"},{"text":"LinkedIn","value":"linkedin"},{"text":"Twitter","value":"twitter"},{"text":"Email","value":"email"},{"text":"Website","value":"website"}]}	\N	\N	f	f	5	full	\N	\N	\N	f	\N	\N	\N
56	social_links	order	\N	input	\N	\N	\N	f	f	6	full	\N	\N	\N	f	\N	\N	\N
57	social_links	visible	\N	boolean	\N	\N	\N	f	f	7	full	\N	\N	\N	f	\N	\N	\N
58	work_projects	category	\N	select-dropdown	{"choices":[{"text":"Employment","value":"employment"},{"text":"Research","value":"research"},{"text":"Education/Community","value":"education"},{"text":"Hackathon","value":"hackathon"},{"text":"Open Source","value":"open-source"}]}	labels	{"choices":[{"text":"Employment","value":"employment","foreground":"#FFFFFF","background":"#2563EB"},{"text":"Research","value":"research","foreground":"#FFFFFF","background":"#7C3AED"},{"text":"Education/Community","value":"education","foreground":"#FFFFFF","background":"#059669"},{"text":"Hackathon","value":"hackathon","foreground":"#FFFFFF","background":"#DC2626"},{"text":"Open Source","value":"open-source","foreground":"#FFFFFF","background":"#EA580C"}]}	f	f	17	half	\N	\N	\N	f	\N	\N	\N
\.


--
-- Data for Name: directus_files; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_files (id, storage, filename_disk, filename_download, title, type, folder, uploaded_by, created_on, modified_by, modified_on, charset, filesize, width, height, duration, embed, description, location, tags, metadata, focal_point_x, focal_point_y, tus_id, tus_data, uploaded_on) FROM stdin;
\.


--
-- Data for Name: directus_flows; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_flows (id, name, icon, color, description, status, trigger, accountability, options, operation, date_created, user_created) FROM stdin;
\.


--
-- Data for Name: directus_folders; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_folders (id, name, parent) FROM stdin;
\.


--
-- Data for Name: directus_migrations; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_migrations (version, name, "timestamp") FROM stdin;
20201028A	Remove Collection Foreign Keys	2025-10-14 00:47:38.551024+00
20201029A	Remove System Relations	2025-10-14 00:47:38.555933+00
20201029B	Remove System Collections	2025-10-14 00:47:38.560903+00
20201029C	Remove System Fields	2025-10-14 00:47:38.567205+00
20201105A	Add Cascade System Relations	2025-10-14 00:47:38.619049+00
20201105B	Change Webhook URL Type	2025-10-14 00:47:38.62985+00
20210225A	Add Relations Sort Field	2025-10-14 00:47:38.636329+00
20210304A	Remove Locked Fields	2025-10-14 00:47:38.640165+00
20210312A	Webhooks Collections Text	2025-10-14 00:47:38.648843+00
20210331A	Add Refresh Interval	2025-10-14 00:47:38.652108+00
20210415A	Make Filesize Nullable	2025-10-14 00:47:38.658607+00
20210416A	Add Collections Accountability	2025-10-14 00:47:38.661895+00
20210422A	Remove Files Interface	2025-10-14 00:47:38.663762+00
20210506A	Rename Interfaces	2025-10-14 00:47:38.672708+00
20210510A	Restructure Relations	2025-10-14 00:47:38.684629+00
20210518A	Add Foreign Key Constraints	2025-10-14 00:47:38.688975+00
20210519A	Add System Fk Triggers	2025-10-14 00:47:38.709976+00
20210521A	Add Collections Icon Color	2025-10-14 00:47:38.712856+00
20210525A	Add Insights	2025-10-14 00:47:38.723276+00
20210608A	Add Deep Clone Config	2025-10-14 00:47:38.726683+00
20210626A	Change Filesize Bigint	2025-10-14 00:47:38.736164+00
20210716A	Add Conditions to Fields	2025-10-14 00:47:38.739483+00
20210721A	Add Default Folder	2025-10-14 00:47:38.74512+00
20210802A	Replace Groups	2025-10-14 00:47:38.748708+00
20210803A	Add Required to Fields	2025-10-14 00:47:38.751622+00
20210805A	Update Groups	2025-10-14 00:47:38.754387+00
20210805B	Change Image Metadata Structure	2025-10-14 00:47:38.757041+00
20210811A	Add Geometry Config	2025-10-14 00:47:38.759877+00
20210831A	Remove Limit Column	2025-10-14 00:47:38.762447+00
20210903A	Add Auth Provider	2025-10-14 00:47:38.773902+00
20210907A	Webhooks Collections Not Null	2025-10-14 00:47:38.780424+00
20210910A	Move Module Setup	2025-10-14 00:47:38.784206+00
20210920A	Webhooks URL Not Null	2025-10-14 00:47:38.790448+00
20210924A	Add Collection Organization	2025-10-14 00:47:38.795242+00
20210927A	Replace Fields Group	2025-10-14 00:47:38.802002+00
20210927B	Replace M2M Interface	2025-10-14 00:47:38.803841+00
20210929A	Rename Login Action	2025-10-14 00:47:38.805698+00
20211007A	Update Presets	2025-10-14 00:47:38.810576+00
20211009A	Add Auth Data	2025-10-14 00:47:38.813054+00
20211016A	Add Webhook Headers	2025-10-14 00:47:38.815557+00
20211103A	Set Unique to User Token	2025-10-14 00:47:38.818254+00
20211103B	Update Special Geometry	2025-10-14 00:47:38.820196+00
20211104A	Remove Collections Listing	2025-10-14 00:47:38.822597+00
20211118A	Add Notifications	2025-10-14 00:47:38.830991+00
20211211A	Add Shares	2025-10-14 00:47:38.843628+00
20211230A	Add Project Descriptor	2025-10-14 00:47:38.846485+00
20220303A	Remove Default Project Color	2025-10-14 00:47:38.854108+00
20220308A	Add Bookmark Icon and Color	2025-10-14 00:47:38.857385+00
20220314A	Add Translation Strings	2025-10-14 00:47:38.860129+00
20220322A	Rename Field Typecast Flags	2025-10-14 00:47:38.863193+00
20220323A	Add Field Validation	2025-10-14 00:47:38.865785+00
20220325A	Fix Typecast Flags	2025-10-14 00:47:38.868507+00
20220325B	Add Default Language	2025-10-14 00:47:38.876111+00
20220402A	Remove Default Value Panel Icon	2025-10-14 00:47:38.882355+00
20220429A	Add Flows	2025-10-14 00:47:38.900024+00
20220429B	Add Color to Insights Icon	2025-10-14 00:47:38.903112+00
20220429C	Drop Non Null From IP of Activity	2025-10-14 00:47:38.90595+00
20220429D	Drop Non Null From Sender of Notifications	2025-10-14 00:47:38.908832+00
20220614A	Rename Hook Trigger to Event	2025-10-14 00:47:38.910871+00
20220801A	Update Notifications Timestamp Column	2025-10-14 00:47:38.917482+00
20220802A	Add Custom Aspect Ratios	2025-10-14 00:47:38.920018+00
20220826A	Add Origin to Accountability	2025-10-14 00:47:38.923763+00
20230401A	Update Material Icons	2025-10-14 00:47:38.930725+00
20230525A	Add Preview Settings	2025-10-14 00:47:38.933343+00
20230526A	Migrate Translation Strings	2025-10-14 00:47:38.939059+00
20230721A	Require Shares Fields	2025-10-14 00:47:38.943597+00
20230823A	Add Content Versioning	2025-10-14 00:47:38.960094+00
20230927A	Themes	2025-10-14 00:47:38.982785+00
20231009A	Update CSV Fields to Text	2025-10-14 00:47:38.98856+00
20231009B	Update Panel Options	2025-10-14 00:47:38.99232+00
20231010A	Add Extensions	2025-10-14 00:47:38.996871+00
20231215A	Add Focalpoints	2025-10-14 00:47:39.000585+00
20240122A	Add Report URL Fields	2025-10-14 00:47:39.004356+00
20240204A	Marketplace	2025-10-14 00:47:39.032089+00
20240305A	Change Useragent Type	2025-10-14 00:47:39.042967+00
20240311A	Deprecate Webhooks	2025-10-14 00:47:39.050738+00
20240422A	Public Registration	2025-10-14 00:47:39.057077+00
20240515A	Add Session Window	2025-10-14 00:47:39.060911+00
20240701A	Add Tus Data	2025-10-14 00:47:39.064797+00
20240716A	Update Files Date Fields	2025-10-14 00:47:39.072148+00
20240806A	Permissions Policies	2025-10-14 00:47:39.105688+00
20240817A	Update Icon Fields Length	2025-10-14 00:47:39.138801+00
20240909A	Separate Comments	2025-10-14 00:47:39.149577+00
20240909B	Consolidate Content Versioning	2025-10-14 00:47:39.153418+00
20240924A	Migrate Legacy Comments	2025-10-14 00:47:39.158756+00
20240924B	Populate Versioning Deltas	2025-10-14 00:47:39.162315+00
20250224A	Visual Editor	2025-10-14 00:47:39.165965+00
20250609A	License Banner	2025-10-14 00:47:39.169936+00
20250613A	Add Project ID	2025-10-14 00:47:39.179309+00
20250718A	Add Direction	2025-10-14 00:47:39.183371+00
20250813A	Add MCP	2025-10-14 00:47:39.187058+00
\.


--
-- Data for Name: directus_notifications; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_notifications (id, "timestamp", status, recipient, sender, subject, message, collection, item) FROM stdin;
\.


--
-- Data for Name: directus_operations; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_operations (id, name, key, type, position_x, position_y, options, resolve, reject, flow, date_created, user_created) FROM stdin;
\.


--
-- Data for Name: directus_panels; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_panels (id, dashboard, name, icon, color, show_header, note, type, position_x, position_y, width, height, options, date_created, user_created) FROM stdin;
\.


--
-- Data for Name: directus_permissions; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_permissions (id, collection, action, permissions, validation, presets, fields, policy) FROM stdin;
1	posts	read	\N	\N	\N	*	abf8a154-5b1c-4a46-ac9c-7300570f4f17
2	profile	read	\N	\N	\N	*	abf8a154-5b1c-4a46-ac9c-7300570f4f17
3	skills	read	\N	\N	\N	*	abf8a154-5b1c-4a46-ac9c-7300570f4f17
4	social_links	read	{"_and":[{"visible":{"_eq":true}}]}	\N	\N	*	abf8a154-5b1c-4a46-ac9c-7300570f4f17
5	work_projects	read	{"_and":[{"status":{"_eq":"published"}}]}	\N	\N	*	abf8a154-5b1c-4a46-ac9c-7300570f4f17
\.


--
-- Data for Name: directus_policies; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_policies (id, name, icon, description, ip_access, enforce_tfa, admin_access, app_access) FROM stdin;
abf8a154-5b1c-4a46-ac9c-7300570f4f17	$t:public_label	public	$t:public_description	\N	f	f	f
211b930e-e270-4b77-aa7d-283b3aa255e4	Administrator	verified	$t:admin_description	\N	f	t	t
\.


--
-- Data for Name: directus_presets; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_presets (id, bookmark, "user", role, collection, search, layout, layout_query, layout_options, refresh_interval, filter, icon, color) FROM stdin;
3	\N	446b0591-88bd-4122-8877-6ff5b00e4201	\N	skills	\N	\N	{"tabular":{"fields":["category","name","order","proficiency","featured"],"sort":["featured"],"page":1}}	\N	\N	\N	bookmark	\N
1	\N	446b0591-88bd-4122-8877-6ff5b00e4201	\N	posts	\N	\N	{"tabular":{"page":1,"fields":["content","published","title"]}}	{"tabular":{"widths":{"content":160,"published":160,"title":560}}}	\N	\N	bookmark	\N
2	\N	446b0591-88bd-4122-8877-6ff5b00e4201	\N	work_projects	\N	\N	{"tabular":{"fields":["company","slug","status","title"],"page":1}}	{"tabular":{"widths":{"company":358,"slug":160,"status":160,"title":160}}}	\N	\N	bookmark	\N
\.


--
-- Data for Name: directus_relations; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_relations (id, many_collection, many_field, one_collection, one_field, one_collection_field, one_allowed_collections, junction_field, sort_field, one_deselect_action) FROM stdin;
\.


--
-- Data for Name: directus_revisions; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_revisions (id, activity, collection, item, data, delta, parent, version) FROM stdin;
1	2	directus_settings	1	{"id":1,"project_name":"Directus","project_url":null,"project_color":"#6644FF","project_logo":null,"public_foreground":null,"public_background":null,"public_note":null,"auth_login_attempts":25,"auth_password_policy":null,"storage_asset_transform":"all","storage_asset_presets":null,"custom_css":null,"storage_default_folder":null,"basemaps":null,"mapbox_key":null,"module_bar":null,"project_descriptor":null,"default_language":"en-US","custom_aspect_ratios":null,"public_favicon":null,"default_appearance":"auto","default_theme_light":null,"theme_light_overrides":null,"default_theme_dark":null,"theme_dark_overrides":null,"report_error_url":null,"report_bug_url":null,"report_feature_url":null,"public_registration":false,"public_registration_verify_email":true,"public_registration_role":null,"public_registration_email_filter":null,"visual_editor_urls":null,"accepted_terms":true,"project_id":"0199e02f-e4a9-7130-9a23-b23adc90f974","mcp_enabled":false,"mcp_allow_deletes":false,"mcp_prompts_collection":null,"mcp_system_prompt_enabled":true,"mcp_system_prompt":null}	{"accepted_terms":true}	\N	\N
2	3	directus_fields	1	{"sort":1,"hidden":true,"interface":"input","readonly":true,"field":"id","collection":"posts"}	{"sort":1,"hidden":true,"interface":"input","readonly":true,"field":"id","collection":"posts"}	\N	\N
3	4	directus_fields	2	{"sort":2,"special":["date-created"],"interface":"datetime","readonly":true,"hidden":true,"width":"half","display":"datetime","display_options":{"relative":true},"field":"date_created","collection":"posts"}	{"sort":2,"special":["date-created"],"interface":"datetime","readonly":true,"hidden":true,"width":"half","display":"datetime","display_options":{"relative":true},"field":"date_created","collection":"posts"}	\N	\N
4	5	directus_fields	3	{"sort":3,"special":["date-updated"],"interface":"datetime","readonly":true,"hidden":true,"width":"half","display":"datetime","display_options":{"relative":true},"field":"date_updated","collection":"posts"}	{"sort":3,"special":["date-updated"],"interface":"datetime","readonly":true,"hidden":true,"width":"half","display":"datetime","display_options":{"relative":true},"field":"date_updated","collection":"posts"}	\N	\N
5	6	directus_collections	posts	{"singleton":false,"collection":"posts"}	{"singleton":false,"collection":"posts"}	\N	\N
6	7	directus_fields	4	{"sort":4,"interface":"input","special":null,"required":true,"collection":"posts","field":"title"}	{"sort":4,"interface":"input","special":null,"required":true,"collection":"posts","field":"title"}	\N	\N
7	8	directus_fields	5	{"sort":5,"interface":"input-rich-text-html","special":null,"required":true,"collection":"posts","field":"content"}	{"sort":5,"interface":"input-rich-text-html","special":null,"required":true,"collection":"posts","field":"content"}	\N	\N
8	9	directus_fields	6	{"sort":6,"interface":"boolean","special":["cast-boolean"],"collection":"posts","field":"published"}	{"sort":6,"interface":"boolean","special":["cast-boolean"],"collection":"posts","field":"published"}	\N	\N
9	10	directus_permissions	1	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":null,"validation":null,"fields":["*"],"presets":null,"collection":"posts","action":"read"}	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":null,"validation":null,"fields":["*"],"presets":null,"collection":"posts","action":"read"}	\N	\N
10	12	posts	1	{"title":"Welcome to Astro + Hono + Directus","content":"<p>This is a full-stack TypeScript application demonstrating how to use Directus as a headless CMS. The architecture consists of:</p>\\n<ul>\\n<li>Astro for server-side rendering</li>\\n<li>Hono for the API layer</li>\\n<li>Directus for content management</li>\\n<li>Traefik for routing</li>\\n</ul>\\n<p>All running in Docker containers!</p>"}	{"title":"Welcome to Astro + Hono + Directus","content":"<p>This is a full-stack TypeScript application demonstrating how to use Directus as a headless CMS. The architecture consists of:</p>\\n<ul>\\n<li>Astro for server-side rendering</li>\\n<li>Hono for the API layer</li>\\n<li>Directus for content management</li>\\n<li>Traefik for routing</li>\\n</ul>\\n<p>All running in Docker containers!</p>"}	\N	\N
11	13	posts	1	{"id":1,"date_created":"2025-10-14T02:29:54.411Z","date_updated":"2025-10-14T02:30:05.438Z","title":"Welcome to Astro + Hono + Directus","content":"<p>This is a full-stack TypeScript application demonstrating how to use Directus as a headless CMS. The architecture consists of:</p>\\n<ul>\\n<li>Astro for server-side rendering</li>\\n<li>Hono for the API layer</li>\\n<li>Directus for content management</li>\\n<li>Traefik for routing</li>\\n</ul>\\n<p>All running in Docker containers!</p>","published":true}	{"published":true,"date_updated":"2025-10-14T02:30:05.438Z"}	\N	\N
12	14	posts	2	{"title":"Why Use a Headless CMS?","content":"<p>Headless CMS architecture separates content management from presentation:</p>\\n<ul>\\n<li>Content editors use a friendly UI (Directus)</li>\\n<li>Developers fetch content via API</li>\\n<li>Frontend can be any technology</li>\\n<li>Content is reusable across multiple platforms</li>\\n</ul>\\n<p>Perfect for modern web applications!</p>","published":true}	{"title":"Why Use a Headless CMS?","content":"<p>Headless CMS architecture separates content management from presentation:</p>\\n<ul>\\n<li>Content editors use a friendly UI (Directus)</li>\\n<li>Developers fetch content via API</li>\\n<li>Frontend can be any technology</li>\\n<li>Content is reusable across multiple platforms</li>\\n</ul>\\n<p>Perfect for modern web applications!</p>","published":true}	\N	\N
13	15	posts	3	{"title":"Building with TypeScript","content":"<p>This entire stack is built with TypeScript:</p>\\n<ul>\\n<li>Type-safe API with Hono</li>\\n<li>Type-safe frontend with Astro</li>\\n<li>Type-safe Directus SDK</li>\\n</ul>\\n<p>TypeScript catches errors during development, not in production!</p>"}	{"title":"Building with TypeScript","content":"<p>This entire stack is built with TypeScript:</p>\\n<ul>\\n<li>Type-safe API with Hono</li>\\n<li>Type-safe frontend with Astro</li>\\n<li>Type-safe Directus SDK</li>\\n</ul>\\n<p>TypeScript catches errors during development, not in production!</p>"}	\N	\N
14	16	posts	3	{"id":3,"date_created":"2025-10-14T02:31:04.700Z","date_updated":"2025-10-14T02:31:07.858Z","title":"Building with TypeScript","content":"<p>This entire stack is built with TypeScript:</p>\\n<ul>\\n<li>Type-safe API with Hono</li>\\n<li>Type-safe frontend with Astro</li>\\n<li>Type-safe Directus SDK</li>\\n</ul>\\n<p>TypeScript catches errors during development, not in production!</p>","published":true}	{"published":true,"date_updated":"2025-10-14T02:31:07.858Z"}	\N	\N
15	21	directus_fields	7	{"sort":7,"interface":"input-code","special":null,"options":{"language":"markdown"},"collection":"posts","field":"content"}	{"sort":7,"interface":"input-code","special":null,"options":{"language":"markdown"},"collection":"posts","field":"content"}	\N	\N
37	44	directus_fields	25	{"sort":18,"interface":"input-multiline","collection":"profile","field":"connect_description"}	{"sort":18,"interface":"input-multiline","collection":"profile","field":"connect_description"}	\N	\N
38	45	directus_fields	26	{"sort":19,"interface":"input","collection":"profile","field":"footer_copyright"}	{"sort":19,"interface":"input","collection":"profile","field":"footer_copyright"}	\N	\N
39	46	directus_fields	27	{"sort":20,"interface":"input","collection":"profile","field":"footer_attribution"}	{"sort":20,"interface":"input","collection":"profile","field":"footer_attribution"}	\N	\N
16	22	posts	4	{"published":true,"title":"Welcome to Astro + Hono + Directus","content":"# Welcome to the Stack!\\n\\nThis is a **full-stack TypeScript application** demonstrating how to use Directus as a headless CMS.\\n\\n## Architecture\\n\\nThe architecture consists of:\\n- **Astro** for server-side rendering\\n- **Hono** for the API layer\\n- **Directus** for content management\\n- **Traefik** for routing\\n\\nAll running in Docker containers! 🚀\\n\\n## Features\\n\\n- Server-side rendering with Astro\\n- Type-safe API with Hono\\n- Markdown content with frontmatter support\\n- Automatic routing via Traefik\\n"}	{"published":true,"title":"Welcome to Astro + Hono + Directus","content":"# Welcome to the Stack!\\n\\nThis is a **full-stack TypeScript application** demonstrating how to use Directus as a headless CMS.\\n\\n## Architecture\\n\\nThe architecture consists of:\\n- **Astro** for server-side rendering\\n- **Hono** for the API layer\\n- **Directus** for content management\\n- **Traefik** for routing\\n\\nAll running in Docker containers! 🚀\\n\\n## Features\\n\\n- Server-side rendering with Astro\\n- Type-safe API with Hono\\n- Markdown content with frontmatter support\\n- Automatic routing via Traefik\\n"}	\N	\N
17	23	posts	5	{"title":"Why Use a Headless CMS?","content":"## The Power of Headless CMS\\n\\nHeadless CMS architecture **separates content management from presentation:**\\n\\n### Benefits\\n\\n1. **Content editors** use a friendly UI (Directus)\\n2. **Developers** fetch content via API\\n3. **Frontend** can be any technology\\n4. **Content** is reusable across multiple platforms\\n\\n> Perfect for modern web applications!\\n\\n### Use Cases\\n\\n- Websites and web apps\\n- Mobile applications\\n- Digital signage\\n- IoT devices\\n","published":true}	{"title":"Why Use a Headless CMS?","content":"## The Power of Headless CMS\\n\\nHeadless CMS architecture **separates content management from presentation:**\\n\\n### Benefits\\n\\n1. **Content editors** use a friendly UI (Directus)\\n2. **Developers** fetch content via API\\n3. **Frontend** can be any technology\\n4. **Content** is reusable across multiple platforms\\n\\n> Perfect for modern web applications!\\n\\n### Use Cases\\n\\n- Websites and web apps\\n- Mobile applications\\n- Digital signage\\n- IoT devices\\n","published":true}	\N	\N
18	24	posts	6	{"title":"Building with TypeScript","published":true,"content":"# TypeScript Everywhere\\n\\nThis entire stack is built with **TypeScript**:\\n\\n## Frontend\\n- Type-safe components with Astro\\n- Compile-time error checking\\n- IntelliSense support\\n\\n## Backend\\n- Type-safe API with Hono\\n- Type-safe Directus SDK\\n- Type-safe routing\\n\\n```typescript\\n// Example: Type-safe API call\\nconst posts = await api.getPosts()\\n// posts is correctly typed as Post[]\\n```\\n\\nTypeScript catches errors during *development*, not in **production**!\\n"}	{"title":"Building with TypeScript","published":true,"content":"# TypeScript Everywhere\\n\\nThis entire stack is built with **TypeScript**:\\n\\n## Frontend\\n- Type-safe components with Astro\\n- Compile-time error checking\\n- IntelliSense support\\n\\n## Backend\\n- Type-safe API with Hono\\n- Type-safe Directus SDK\\n- Type-safe routing\\n\\n```typescript\\n// Example: Type-safe API call\\nconst posts = await api.getPosts()\\n// posts is correctly typed as Post[]\\n```\\n\\nTypeScript catches errors during *development*, not in **production**!\\n"}	\N	\N
19	26	directus_fields	8	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"profile"}	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"profile"}	\N	\N
20	27	directus_collections	profile	{"singleton":true,"icon":"person","note":"Personal and professional information","collection":"profile"}	{"singleton":true,"icon":"person","note":"Personal and professional information","collection":"profile"}	\N	\N
21	28	directus_fields	9	{"sort":2,"required":true,"interface":"input","options":{"placeholder":"Full Name"},"collection":"profile","field":"full_name"}	{"sort":2,"required":true,"interface":"input","options":{"placeholder":"Full Name"},"collection":"profile","field":"full_name"}	\N	\N
22	29	directus_fields	10	{"sort":3,"required":true,"interface":"input","collection":"profile","field":"first_name"}	{"sort":3,"required":true,"interface":"input","collection":"profile","field":"first_name"}	\N	\N
23	30	directus_fields	11	{"sort":4,"required":true,"interface":"input","collection":"profile","field":"last_name"}	{"sort":4,"required":true,"interface":"input","collection":"profile","field":"last_name"}	\N	\N
24	31	directus_fields	12	{"sort":5,"required":true,"interface":"input","options":{"placeholder":"Full Stack Developer"},"collection":"profile","field":"title"}	{"sort":5,"required":true,"interface":"input","options":{"placeholder":"Full Stack Developer"},"collection":"profile","field":"title"}	\N	\N
25	32	directus_fields	13	{"sort":6,"required":true,"interface":"input-multiline","collection":"profile","field":"description"}	{"sort":6,"required":true,"interface":"input-multiline","collection":"profile","field":"description"}	\N	\N
26	33	directus_fields	14	{"sort":7,"required":true,"interface":"input","options":{"placeholder":"email@example.com"},"collection":"profile","field":"email"}	{"sort":7,"required":true,"interface":"input","options":{"placeholder":"email@example.com"},"collection":"profile","field":"email"}	\N	\N
27	34	directus_fields	15	{"sort":8,"interface":"input","collection":"profile","field":"location"}	{"sort":8,"interface":"input","collection":"profile","field":"location"}	\N	\N
28	35	directus_fields	16	{"sort":9,"interface":"input","collection":"profile","field":"portfolio_year"}	{"sort":9,"interface":"input","collection":"profile","field":"portfolio_year"}	\N	\N
29	36	directus_fields	17	{"sort":10,"interface":"boolean","collection":"profile","field":"availability"}	{"sort":10,"interface":"boolean","collection":"profile","field":"availability"}	\N	\N
30	37	directus_fields	18	{"sort":11,"interface":"input","collection":"profile","field":"availability_text"}	{"sort":11,"interface":"input","collection":"profile","field":"availability_text"}	\N	\N
31	38	directus_fields	19	{"sort":12,"interface":"input","collection":"profile","field":"current_role_title"}	{"sort":12,"interface":"input","collection":"profile","field":"current_role_title"}	\N	\N
32	39	directus_fields	20	{"sort":13,"interface":"input","collection":"profile","field":"current_role_company"}	{"sort":13,"interface":"input","collection":"profile","field":"current_role_company"}	\N	\N
33	40	directus_fields	21	{"sort":14,"interface":"input","collection":"profile","field":"current_role_duration"}	{"sort":14,"interface":"input","collection":"profile","field":"current_role_duration"}	\N	\N
34	41	directus_fields	22	{"sort":15,"interface":"input","collection":"profile","field":"work_section_title"}	{"sort":15,"interface":"input","collection":"profile","field":"work_section_title"}	\N	\N
35	42	directus_fields	23	{"sort":16,"interface":"input","collection":"profile","field":"work_section_date_range"}	{"sort":16,"interface":"input","collection":"profile","field":"work_section_date_range"}	\N	\N
36	43	directus_fields	24	{"sort":17,"interface":"input","collection":"profile","field":"connect_title"}	{"sort":17,"interface":"input","collection":"profile","field":"connect_title"}	\N	\N
145	168	posts	8	{"title":"From v0.dev Template to Production: A Technical Deep-Dive","content":"# From v0.dev Template to Production: A Technical Deep-Dive\\n\\nMost tutorials stop at \\"here's the template.\\" This one shows what happens after: integrating a real CMS, building a type-safe API layer, and deploying to production with Docker.\\n\\n## The Challenge: Static → Dynamic\\n\\nv0.dev gives you beautiful UI components, but they're hardcoded. Here's what that looks like:\\n\\n```tsx\\n// Before: Hardcoded in component\\nconst projects = [\\n  { title: \\"Project 1\\", description: \\"...\\" },\\n  { title: \\"Project 2\\", description: \\"...\\" }\\n]\\n```\\n\\nThe goal: Replace this with a real CMS so content editors can update projects without touching code:\\n\\n```tsx\\n// After: Fetched from Directus via API\\nconst projects = await api.getWorkProjects()\\n```\\n\\nThis post shows exactly how to make that transformation across the entire stack.\\n\\n## Architecture Decisions: The \\"Why\\" Behind Each Choice\\n\\n### Astro over Next.js\\n\\n**Why:** Content-first sites don't need React's full runtime. Astro ships zero JavaScript by default, uses server-side rendering, and has faster build times. For a portfolio site, this means better performance and simpler deployment.\\n\\n### Hono over Express\\n\\n**Why:** Hono is lightweight (12KB vs Express's 200KB+), has better TypeScript DX with type-safe routing, and is edge-ready. The API becomes a thin layer between Astro and Directus:\\n\\n```typescript\\n// api/src/index.ts - Simple, type-safe routes\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // Type-safe param extraction\\n  const project = await getWorkProject(slug)\\n  if (!project) {\\n    return c.json({ error: 'Work project not found' }, 404)\\n  }\\n  return c.json({ data: project })\\n})\\n```\\n\\n### Directus over Strapi/Payload\\n\\n**Why:** Directus has the best admin UI, uses PostgreSQL (no vendor lock-in), supports relational data naturally, and provides a TypeScript SDK with auto-generated types. Content editors get a professional interface without custom development.\\n\\n### Docker Compose for Development\\n\\n**Why:** Identical dev/prod environments. No \\"works on my machine\\" issues. One command starts everything:\\n\\n```yaml\\n# compose.yaml - The entire stack\\nservices:\\n  api:\\n    build: ./api\\n    networks:\\n      - homelab-network\\n    expose:\\n      - \\"3000\\"\\n    healthcheck:\\n      test: [\\"CMD\\", \\"node\\", \\"-e\\", \\"require('http').get('http://127.0.0.1:3000/health', ...)\\"]\\n      interval: 30s\\n\\n  frontend:\\n    build: ./frontend\\n    environment:\\n      API_URL: http://astro-hono-api:3000\\n      PUBLIC_API_URL: https://api.b28.dev\\n    depends_on:\\n      api:\\n        condition: service_healthy\\n    networks:\\n      - homelab-network\\n    expose:\\n      - \\"4321\\"\\n```\\n\\nDocker networking handles service discovery. Healthchecks ensure API is ready before frontend starts. Traefik labels provide automatic reverse proxy configuration.\\n\\n### Cloudflare Tunnels for Deployment\\n\\n**Why:** No port forwarding, no firewall configuration, free HTTPS, built-in DDoS protection. Traditional self-hosting required dynamic DNS, SSL certificates, and NAT traversal. Cloudflare Tunnels eliminates all of that:\\n\\n```bash\\n# Simple, secure deployment\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\n## Implementation Deep-Dive\\n\\n### 1. Directus Schema Design\\n\\nThe schema defines four collections. Here's the WorkProject schema as defined in TypeScript:\\n\\n```typescript\\n// api/src/lib/directus.ts\\ninterface WorkProject {\\n  id: number\\n  status: string\\n  title: string\\n  slug: string              // URL-friendly identifier\\n  company: string\\n  role: string\\n  year: string\\n  duration?: string         // Optional: \\"3 months\\", \\"1 year\\"\\n  description: string       // Short summary\\n  content?: string          // Full markdown case study\\n  technologies: string[]    // Array of tech tags\\n  featured: boolean         // Show on homepage\\n  order?: number            // Manual ordering\\n  team?: string            // Team composition\\n  live_url?: string        // Deployed project link\\n  case_study_url?: string  // External writeup\\n  category?: string        // employment | hackathon | research\\n}\\n```\\n\\nKey decisions:\\n- **`slug`** for SEO-friendly URLs\\n- **`content`** as markdown for rich formatting\\n- **`featured`** and **`order`** for manual curation\\n- **`category`** to distinguish project types\\n\\n### 2. Type-Safe API Layer with Hono\\n\\nThe API layer connects Directus to Astro. It uses the Directus SDK with typed requests:\\n\\n```typescript\\n// api/src/lib/directus.ts - Directus client with TypeScript\\nimport { createDirectus, rest, readItems, readSingleton } from '@directus/sdk'\\n\\ninterface Schema {\\n  posts: Post[]\\n  profile: Profile\\n  work_projects: WorkProject[]\\n  skills: Skill[]\\n  social_links: SocialLink[]\\n}\\n\\nconst directusUrl = process.env.DIRECTUS_URL || 'http://directus:8055'\\nexport const directus = createDirectus<Schema>(directusUrl).with(rest())\\n\\n// Type-safe queries\\nexport const getWorkProjects = async () => {\\n  return await directus.request(\\n    readItems('work_projects', {\\n      filter: {\\n        status: { _eq: 'published' }\\n      },\\n      sort: ['order'],\\n      limit: -1\\n    })\\n  )\\n}\\n\\nexport const getWorkProject = async (slug: string) => {\\n  const results = await directus.request(\\n    readItems('work_projects', {\\n      filter: {\\n        slug: { _eq: slug },\\n        status: { _eq: 'published' }\\n      },\\n      limit: 1\\n    })\\n  )\\n  return results[0] || null\\n}\\n```\\n\\nThe magic: **TypeScript knows the exact shape of the data at every step**. If Directus changes the schema, TypeScript errors surface immediately.\\n\\n### 3. Frontend API Client\\n\\nThe frontend talks to the Hono API (not directly to Directus). This provides a security boundary and type safety:\\n\\n```typescript\\n// frontend/src/lib/api.ts\\nconst API_BASE_URL = import.meta.env.API_URL || 'http://astro-hono-api:3000'\\n\\nexport interface WorkProject {\\n  id: number\\n  slug: string\\n  title: string\\n  company: string\\n  role: string\\n  year: string\\n  technologies: string[]\\n  featured: boolean\\n  // ... full interface\\n}\\n\\nexport interface WorkProjectResponse {\\n  data: WorkProject\\n}\\n\\nexport const api = {\\n  async getWorkProject(slug: string): Promise<WorkProjectResponse> {\\n    const response = await fetch(\\n      `${API_BASE_URL}/api/work-projects/${encodeURIComponent(slug)}`\\n    )\\n    if (!response.ok) throw new Error('Failed to fetch work project')\\n    return response.json()\\n  }\\n}\\n```\\n\\nEnvironment variables switch between:\\n- **Development:** `http://astro-hono-api:3000` (Docker internal network)\\n- **Production:** `https://api.b28.dev` (Cloudflare Tunnel)\\n\\n### 4. Content Adapter Pattern\\n\\nThis is the key architectural pattern. Astro expects content collections, but we're using Directus. The adapter bridges the gap:\\n\\n```typescript\\n// frontend/src/content/index.ts - Making Directus look like Astro\\nexport async function getWorkProject(slug: string) {\\n  try {\\n    const response = await api.getWorkProject(slug)\\n    if (response && response.data) {\\n      const project = response.data\\n      // Transform to Astro content collection format\\n      return {\\n        slug: project.slug,\\n        data: {\\n          title: project.title,\\n          company: project.company,\\n          role: project.role,\\n          year: project.year,\\n          description: project.description,\\n          technologies: project.technologies || [],\\n          featured: project.featured,\\n          content: project.content,\\n          team: project.team,\\n          live_url: project.live_url\\n        }\\n      }\\n    }\\n  } catch (error) {\\n    console.error(`Error fetching work project ${slug}:`, error)\\n  }\\n  return null\\n}\\n```\\n\\nThis pattern means:\\n- **Astro pages remain unchanged** - they still call `getWorkProject(slug)`\\n- **CMS can be swapped** - just rewrite the adapter\\n- **Type safety preserved** - TypeScript enforces the contract\\n\\n### 5. Dynamic Routes in Astro\\n\\nWith the adapter in place, Astro dynamic routes work naturally:\\n\\n```astro\\n---\\n// pages/work/[slug].astro\\nimport { getWorkProject } from '../../content'\\nimport { marked } from 'marked'\\n\\nconst { slug } = Astro.params\\nconst project = await getWorkProject(slug)\\n\\nif (!project) {\\n  return Astro.redirect('/404')\\n}\\n\\n// Parse markdown content\\nconst contentHtml = project.data.content\\n  ? marked.parse(project.data.content)\\n  : ''\\n---\\n\\n<Layout title={project.data.title}>\\n  <header>\\n    <h1>{project.data.title}</h1>\\n    <p>{project.data.role} @ {project.data.company}</p>\\n    <p>{project.data.year}</p>\\n  </header>\\n\\n  <p>{project.data.description}</p>\\n\\n  <div class=\\"technologies\\">\\n    {project.data.technologies.map(tech => (\\n      <Tag text={tech} variant=\\"tech\\" />\\n    ))}\\n  </div>\\n\\n  {contentHtml && (\\n    <article>\\n      <Fragment set:html={contentHtml} />\\n    </article>\\n  )}\\n</Layout>\\n```\\n\\nThe flow: **URL → Astro → Adapter → API → Directus → PostgreSQL**\\n\\nEach layer adds type safety. If a field is misspelled, TypeScript catches it at build time.\\n\\n## The Type Safety Chain\\n\\nThis is the real power of the architecture. Types flow through every layer:\\n\\n1. **Directus Schema** → Defines collections in the database\\n2. **API TypeScript Interfaces** → Mirror Directus schema exactly\\n3. **Frontend TypeScript Interfaces** → Match API response shapes\\n4. **Astro Components** → Use typed data with autocomplete\\n\\nExample: Adding a new field to WorkProject:\\n\\n1. Add `github_url` field in Directus admin UI\\n2. Update `WorkProject` interface in `api/src/lib/directus.ts`\\n3. Update `WorkProject` interface in `frontend/src/lib/api.ts`\\n4. TypeScript now knows about `project.data.github_url` everywhere\\n\\n**If you forget step 2 or 3, TypeScript errors prevent the build.** This catches bugs before deployment.\\n\\n## Lessons Learned\\n\\n### What Worked Well\\n\\n**1. Type safety across the entire stack caught bugs early**\\nNo more \\"undefined is not an object\\" in production. TypeScript fails the build if interfaces don't match.\\n\\n**2. Directus admin UI = non-developers can update content**\\nMy partner can add projects to my portfolio without asking me to edit code.\\n\\n**3. Docker Compose = identical dev/prod environments**\\nNo surprises. If it works locally, it works in production.\\n\\n**4. Content adapter pattern = easy to swap CMS later**\\nIf I outgrow Directus, I only rewrite `content/index.ts`. Astro pages stay untouched.\\n\\n### What Was Harder Than Expected\\n\\n**1. Getting TypeScript interfaces to match Directus → API → Frontend**\\nInitial mistake: defining interfaces separately in each layer. Solution: Generate types from Directus schema, then reference everywhere.\\n\\n**2. Debugging Docker networking issues**\\nServices couldn't reach each other initially. Solution: All services must be on the same Docker network. Healthchecks prevent race conditions.\\n\\n**3. Initial Directus schema design (went through 3 iterations)**\\nFirst version was too normalized (too many joins). Second version was too flat (duplicated data). Third version: balanced with sensible defaults.\\n\\n### What I'd Do Differently\\n\\n**1. Start with Directus schema design, not UI**\\nI built Astro components first, then tried to fit Directus around them. Should have designed the schema first, then built UI to match.\\n\\n**2. Use Directus TypeScript SDK from the start**\\nI initially wrote raw HTTP requests. The SDK is type-safe and handles auth, filtering, and pagination automatically.\\n\\n**3. Set up Cloudflare Tunnel earlier**\\nWasted time configuring nginx reverse proxy. Cloudflare Tunnel does it all in one command.\\n\\n## The Result\\n\\n**Live at:** https://b28.dev\\n\\n**Capabilities:**\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Type-safe across entire stack\\n- ✅ Docker-deployed (reproducible environments)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Markdown-powered case studies\\n- ✅ SEO-friendly dynamic routes\\n\\n**Performance:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse Score: 95+\\n\\n**Workflow:**\\n1. Edit content in Directus (http://directus.homelab.local)\\n2. Content changes appear instantly (Astro SSR)\\n3. No build required, no deployment pipeline\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots using Directus image relationships\\n- Implement pagination for blog posts\\n- Add search functionality with Directus filtering\\n- Expand skills taxonomy with proficiency levels\\n- Add analytics (privacy-friendly with Umami)\\n\\n**The key win:** All of this can be done in Directus without touching code.\\n\\n---\\n\\n## The Code\\n\\nFull implementation available in my homelab repository. Key files to review:\\n\\n- **API Layer:** `api/src/index.ts` (Hono routes)\\n- **Directus Integration:** `api/src/lib/directus.ts` (Type-safe queries)\\n- **Frontend API Client:** `frontend/src/lib/api.ts` (Fetch wrappers)\\n- **Content Adapter:** `frontend/src/content/index.ts` (Directus → Astro)\\n- **Dynamic Routes:** `frontend/src/pages/work/[slug].astro`\\n- **Docker Setup:** `compose.yaml` (Full stack orchestration)\\n\\n---\\n\\n**Template Credit:** Started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc)\\n\\n**Tech Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Traefik, Cloudflare Tunnels\\n","published":true}	{"title":"From v0.dev Template to Production: A Technical Deep-Dive","content":"# From v0.dev Template to Production: A Technical Deep-Dive\\n\\nMost tutorials stop at \\"here's the template.\\" This one shows what happens after: integrating a real CMS, building a type-safe API layer, and deploying to production with Docker.\\n\\n## The Challenge: Static → Dynamic\\n\\nv0.dev gives you beautiful UI components, but they're hardcoded. Here's what that looks like:\\n\\n```tsx\\n// Before: Hardcoded in component\\nconst projects = [\\n  { title: \\"Project 1\\", description: \\"...\\" },\\n  { title: \\"Project 2\\", description: \\"...\\" }\\n]\\n```\\n\\nThe goal: Replace this with a real CMS so content editors can update projects without touching code:\\n\\n```tsx\\n// After: Fetched from Directus via API\\nconst projects = await api.getWorkProjects()\\n```\\n\\nThis post shows exactly how to make that transformation across the entire stack.\\n\\n## Architecture Decisions: The \\"Why\\" Behind Each Choice\\n\\n### Astro over Next.js\\n\\n**Why:** Content-first sites don't need React's full runtime. Astro ships zero JavaScript by default, uses server-side rendering, and has faster build times. For a portfolio site, this means better performance and simpler deployment.\\n\\n### Hono over Express\\n\\n**Why:** Hono is lightweight (12KB vs Express's 200KB+), has better TypeScript DX with type-safe routing, and is edge-ready. The API becomes a thin layer between Astro and Directus:\\n\\n```typescript\\n// api/src/index.ts - Simple, type-safe routes\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // Type-safe param extraction\\n  const project = await getWorkProject(slug)\\n  if (!project) {\\n    return c.json({ error: 'Work project not found' }, 404)\\n  }\\n  return c.json({ data: project })\\n})\\n```\\n\\n### Directus over Strapi/Payload\\n\\n**Why:** Directus has the best admin UI, uses PostgreSQL (no vendor lock-in), supports relational data naturally, and provides a TypeScript SDK with auto-generated types. Content editors get a professional interface without custom development.\\n\\n### Docker Compose for Development\\n\\n**Why:** Identical dev/prod environments. No \\"works on my machine\\" issues. One command starts everything:\\n\\n```yaml\\n# compose.yaml - The entire stack\\nservices:\\n  api:\\n    build: ./api\\n    networks:\\n      - homelab-network\\n    expose:\\n      - \\"3000\\"\\n    healthcheck:\\n      test: [\\"CMD\\", \\"node\\", \\"-e\\", \\"require('http').get('http://127.0.0.1:3000/health', ...)\\"]\\n      interval: 30s\\n\\n  frontend:\\n    build: ./frontend\\n    environment:\\n      API_URL: http://astro-hono-api:3000\\n      PUBLIC_API_URL: https://api.b28.dev\\n    depends_on:\\n      api:\\n        condition: service_healthy\\n    networks:\\n      - homelab-network\\n    expose:\\n      - \\"4321\\"\\n```\\n\\nDocker networking handles service discovery. Healthchecks ensure API is ready before frontend starts. Traefik labels provide automatic reverse proxy configuration.\\n\\n### Cloudflare Tunnels for Deployment\\n\\n**Why:** No port forwarding, no firewall configuration, free HTTPS, built-in DDoS protection. Traditional self-hosting required dynamic DNS, SSL certificates, and NAT traversal. Cloudflare Tunnels eliminates all of that:\\n\\n```bash\\n# Simple, secure deployment\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\n## Implementation Deep-Dive\\n\\n### 1. Directus Schema Design\\n\\nThe schema defines four collections. Here's the WorkProject schema as defined in TypeScript:\\n\\n```typescript\\n// api/src/lib/directus.ts\\ninterface WorkProject {\\n  id: number\\n  status: string\\n  title: string\\n  slug: string              // URL-friendly identifier\\n  company: string\\n  role: string\\n  year: string\\n  duration?: string         // Optional: \\"3 months\\", \\"1 year\\"\\n  description: string       // Short summary\\n  content?: string          // Full markdown case study\\n  technologies: string[]    // Array of tech tags\\n  featured: boolean         // Show on homepage\\n  order?: number            // Manual ordering\\n  team?: string            // Team composition\\n  live_url?: string        // Deployed project link\\n  case_study_url?: string  // External writeup\\n  category?: string        // employment | hackathon | research\\n}\\n```\\n\\nKey decisions:\\n- **`slug`** for SEO-friendly URLs\\n- **`content`** as markdown for rich formatting\\n- **`featured`** and **`order`** for manual curation\\n- **`category`** to distinguish project types\\n\\n### 2. Type-Safe API Layer with Hono\\n\\nThe API layer connects Directus to Astro. It uses the Directus SDK with typed requests:\\n\\n```typescript\\n// api/src/lib/directus.ts - Directus client with TypeScript\\nimport { createDirectus, rest, readItems, readSingleton } from '@directus/sdk'\\n\\ninterface Schema {\\n  posts: Post[]\\n  profile: Profile\\n  work_projects: WorkProject[]\\n  skills: Skill[]\\n  social_links: SocialLink[]\\n}\\n\\nconst directusUrl = process.env.DIRECTUS_URL || 'http://directus:8055'\\nexport const directus = createDirectus<Schema>(directusUrl).with(rest())\\n\\n// Type-safe queries\\nexport const getWorkProjects = async () => {\\n  return await directus.request(\\n    readItems('work_projects', {\\n      filter: {\\n        status: { _eq: 'published' }\\n      },\\n      sort: ['order'],\\n      limit: -1\\n    })\\n  )\\n}\\n\\nexport const getWorkProject = async (slug: string) => {\\n  const results = await directus.request(\\n    readItems('work_projects', {\\n      filter: {\\n        slug: { _eq: slug },\\n        status: { _eq: 'published' }\\n      },\\n      limit: 1\\n    })\\n  )\\n  return results[0] || null\\n}\\n```\\n\\nThe magic: **TypeScript knows the exact shape of the data at every step**. If Directus changes the schema, TypeScript errors surface immediately.\\n\\n### 3. Frontend API Client\\n\\nThe frontend talks to the Hono API (not directly to Directus). This provides a security boundary and type safety:\\n\\n```typescript\\n// frontend/src/lib/api.ts\\nconst API_BASE_URL = import.meta.env.API_URL || 'http://astro-hono-api:3000'\\n\\nexport interface WorkProject {\\n  id: number\\n  slug: string\\n  title: string\\n  company: string\\n  role: string\\n  year: string\\n  technologies: string[]\\n  featured: boolean\\n  // ... full interface\\n}\\n\\nexport interface WorkProjectResponse {\\n  data: WorkProject\\n}\\n\\nexport const api = {\\n  async getWorkProject(slug: string): Promise<WorkProjectResponse> {\\n    const response = await fetch(\\n      `${API_BASE_URL}/api/work-projects/${encodeURIComponent(slug)}`\\n    )\\n    if (!response.ok) throw new Error('Failed to fetch work project')\\n    return response.json()\\n  }\\n}\\n```\\n\\nEnvironment variables switch between:\\n- **Development:** `http://astro-hono-api:3000` (Docker internal network)\\n- **Production:** `https://api.b28.dev` (Cloudflare Tunnel)\\n\\n### 4. Content Adapter Pattern\\n\\nThis is the key architectural pattern. Astro expects content collections, but we're using Directus. The adapter bridges the gap:\\n\\n```typescript\\n// frontend/src/content/index.ts - Making Directus look like Astro\\nexport async function getWorkProject(slug: string) {\\n  try {\\n    const response = await api.getWorkProject(slug)\\n    if (response && response.data) {\\n      const project = response.data\\n      // Transform to Astro content collection format\\n      return {\\n        slug: project.slug,\\n        data: {\\n          title: project.title,\\n          company: project.company,\\n          role: project.role,\\n          year: project.year,\\n          description: project.description,\\n          technologies: project.technologies || [],\\n          featured: project.featured,\\n          content: project.content,\\n          team: project.team,\\n          live_url: project.live_url\\n        }\\n      }\\n    }\\n  } catch (error) {\\n    console.error(`Error fetching work project ${slug}:`, error)\\n  }\\n  return null\\n}\\n```\\n\\nThis pattern means:\\n- **Astro pages remain unchanged** - they still call `getWorkProject(slug)`\\n- **CMS can be swapped** - just rewrite the adapter\\n- **Type safety preserved** - TypeScript enforces the contract\\n\\n### 5. Dynamic Routes in Astro\\n\\nWith the adapter in place, Astro dynamic routes work naturally:\\n\\n```astro\\n---\\n// pages/work/[slug].astro\\nimport { getWorkProject } from '../../content'\\nimport { marked } from 'marked'\\n\\nconst { slug } = Astro.params\\nconst project = await getWorkProject(slug)\\n\\nif (!project) {\\n  return Astro.redirect('/404')\\n}\\n\\n// Parse markdown content\\nconst contentHtml = project.data.content\\n  ? marked.parse(project.data.content)\\n  : ''\\n---\\n\\n<Layout title={project.data.title}>\\n  <header>\\n    <h1>{project.data.title}</h1>\\n    <p>{project.data.role} @ {project.data.company}</p>\\n    <p>{project.data.year}</p>\\n  </header>\\n\\n  <p>{project.data.description}</p>\\n\\n  <div class=\\"technologies\\">\\n    {project.data.technologies.map(tech => (\\n      <Tag text={tech} variant=\\"tech\\" />\\n    ))}\\n  </div>\\n\\n  {contentHtml && (\\n    <article>\\n      <Fragment set:html={contentHtml} />\\n    </article>\\n  )}\\n</Layout>\\n```\\n\\nThe flow: **URL → Astro → Adapter → API → Directus → PostgreSQL**\\n\\nEach layer adds type safety. If a field is misspelled, TypeScript catches it at build time.\\n\\n## The Type Safety Chain\\n\\nThis is the real power of the architecture. Types flow through every layer:\\n\\n1. **Directus Schema** → Defines collections in the database\\n2. **API TypeScript Interfaces** → Mirror Directus schema exactly\\n3. **Frontend TypeScript Interfaces** → Match API response shapes\\n4. **Astro Components** → Use typed data with autocomplete\\n\\nExample: Adding a new field to WorkProject:\\n\\n1. Add `github_url` field in Directus admin UI\\n2. Update `WorkProject` interface in `api/src/lib/directus.ts`\\n3. Update `WorkProject` interface in `frontend/src/lib/api.ts`\\n4. TypeScript now knows about `project.data.github_url` everywhere\\n\\n**If you forget step 2 or 3, TypeScript errors prevent the build.** This catches bugs before deployment.\\n\\n## Lessons Learned\\n\\n### What Worked Well\\n\\n**1. Type safety across the entire stack caught bugs early**\\nNo more \\"undefined is not an object\\" in production. TypeScript fails the build if interfaces don't match.\\n\\n**2. Directus admin UI = non-developers can update content**\\nMy partner can add projects to my portfolio without asking me to edit code.\\n\\n**3. Docker Compose = identical dev/prod environments**\\nNo surprises. If it works locally, it works in production.\\n\\n**4. Content adapter pattern = easy to swap CMS later**\\nIf I outgrow Directus, I only rewrite `content/index.ts`. Astro pages stay untouched.\\n\\n### What Was Harder Than Expected\\n\\n**1. Getting TypeScript interfaces to match Directus → API → Frontend**\\nInitial mistake: defining interfaces separately in each layer. Solution: Generate types from Directus schema, then reference everywhere.\\n\\n**2. Debugging Docker networking issues**\\nServices couldn't reach each other initially. Solution: All services must be on the same Docker network. Healthchecks prevent race conditions.\\n\\n**3. Initial Directus schema design (went through 3 iterations)**\\nFirst version was too normalized (too many joins). Second version was too flat (duplicated data). Third version: balanced with sensible defaults.\\n\\n### What I'd Do Differently\\n\\n**1. Start with Directus schema design, not UI**\\nI built Astro components first, then tried to fit Directus around them. Should have designed the schema first, then built UI to match.\\n\\n**2. Use Directus TypeScript SDK from the start**\\nI initially wrote raw HTTP requests. The SDK is type-safe and handles auth, filtering, and pagination automatically.\\n\\n**3. Set up Cloudflare Tunnel earlier**\\nWasted time configuring nginx reverse proxy. Cloudflare Tunnel does it all in one command.\\n\\n## The Result\\n\\n**Live at:** https://b28.dev\\n\\n**Capabilities:**\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Type-safe across entire stack\\n- ✅ Docker-deployed (reproducible environments)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Markdown-powered case studies\\n- ✅ SEO-friendly dynamic routes\\n\\n**Performance:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse Score: 95+\\n\\n**Workflow:**\\n1. Edit content in Directus (http://directus.homelab.local)\\n2. Content changes appear instantly (Astro SSR)\\n3. No build required, no deployment pipeline\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots using Directus image relationships\\n- Implement pagination for blog posts\\n- Add search functionality with Directus filtering\\n- Expand skills taxonomy with proficiency levels\\n- Add analytics (privacy-friendly with Umami)\\n\\n**The key win:** All of this can be done in Directus without touching code.\\n\\n---\\n\\n## The Code\\n\\nFull implementation available in my homelab repository. Key files to review:\\n\\n- **API Layer:** `api/src/index.ts` (Hono routes)\\n- **Directus Integration:** `api/src/lib/directus.ts` (Type-safe queries)\\n- **Frontend API Client:** `frontend/src/lib/api.ts` (Fetch wrappers)\\n- **Content Adapter:** `frontend/src/content/index.ts` (Directus → Astro)\\n- **Dynamic Routes:** `frontend/src/pages/work/[slug].astro`\\n- **Docker Setup:** `compose.yaml` (Full stack orchestration)\\n\\n---\\n\\n**Template Credit:** Started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc)\\n\\n**Tech Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Traefik, Cloudflare Tunnels\\n","published":true}	\N	\N
160	191	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T07:03:25.826Z","title":"Building My Portfolio with Claude Code","published":true,"content":"Ten hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (content-friendly framework)\\n- Directus over Strapi (asked Claude once about proper CMS options)\\n- Hono over Express (lighter, learned of it at a Cloudflare tech talk)\\n- Docker Compose over Kubernetes ('tis but homelab)\\n- Cloudflare Tunnels over nginx (simpler)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n"}	{"content":"Ten hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (content-friendly framework)\\n- Directus over Strapi (asked Claude once about proper CMS options)\\n- Hono over Express (lighter, learned of it at a Cloudflare tech talk)\\n- Docker Compose over Kubernetes ('tis but homelab)\\n- Cloudflare Tunnels over nginx (simpler)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n","date_updated":"2025-10-14T07:03:25.826Z"}	\N	\N
40	47	directus_fields	28	{"sort":21,"interface":"input","collection":"profile","field":"footer_year"}	{"sort":21,"interface":"input","collection":"profile","field":"footer_year"}	\N	\N
41	48	directus_fields	29	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"work_projects"}	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"work_projects"}	\N	\N
42	49	directus_collections	work_projects	{"singleton":false,"icon":"work","note":"Portfolio work experience and projects","sort_field":"order","collection":"work_projects"}	{"singleton":false,"icon":"work","note":"Portfolio work experience and projects","sort_field":"order","collection":"work_projects"}	\N	\N
43	50	directus_fields	30	{"sort":2,"required":true,"interface":"select-dropdown","options":{"choices":[{"text":"Draft","value":"draft"},{"text":"Published","value":"published"},{"text":"Archived","value":"archived"}]},"collection":"work_projects","field":"status"}	{"sort":2,"required":true,"interface":"select-dropdown","options":{"choices":[{"text":"Draft","value":"draft"},{"text":"Published","value":"published"},{"text":"Archived","value":"archived"}]},"collection":"work_projects","field":"status"}	\N	\N
44	51	directus_fields	31	{"sort":3,"required":true,"interface":"input","collection":"work_projects","field":"title"}	{"sort":3,"required":true,"interface":"input","collection":"work_projects","field":"title"}	\N	\N
45	52	directus_fields	32	{"sort":4,"required":true,"interface":"input","options":{"slug":true},"collection":"work_projects","field":"slug"}	{"sort":4,"required":true,"interface":"input","options":{"slug":true},"collection":"work_projects","field":"slug"}	\N	\N
46	53	directus_fields	33	{"sort":5,"required":true,"interface":"input","collection":"work_projects","field":"company"}	{"sort":5,"required":true,"interface":"input","collection":"work_projects","field":"company"}	\N	\N
47	54	directus_fields	34	{"sort":6,"required":true,"interface":"input","collection":"work_projects","field":"role"}	{"sort":6,"required":true,"interface":"input","collection":"work_projects","field":"role"}	\N	\N
48	55	directus_fields	35	{"sort":7,"required":true,"interface":"input","collection":"work_projects","field":"year"}	{"sort":7,"required":true,"interface":"input","collection":"work_projects","field":"year"}	\N	\N
49	56	directus_fields	36	{"sort":8,"interface":"input","collection":"work_projects","field":"duration"}	{"sort":8,"interface":"input","collection":"work_projects","field":"duration"}	\N	\N
50	57	directus_fields	37	{"sort":9,"required":true,"interface":"input-multiline","collection":"work_projects","field":"description"}	{"sort":9,"required":true,"interface":"input-multiline","collection":"work_projects","field":"description"}	\N	\N
51	58	directus_fields	38	{"sort":10,"interface":"input-rich-text-md","collection":"work_projects","field":"content"}	{"sort":10,"interface":"input-rich-text-md","collection":"work_projects","field":"content"}	\N	\N
52	59	directus_fields	39	{"sort":11,"required":true,"interface":"tags","collection":"work_projects","field":"technologies"}	{"sort":11,"required":true,"interface":"tags","collection":"work_projects","field":"technologies"}	\N	\N
53	60	directus_fields	40	{"sort":12,"interface":"boolean","collection":"work_projects","field":"featured"}	{"sort":12,"interface":"boolean","collection":"work_projects","field":"featured"}	\N	\N
54	61	directus_fields	41	{"sort":13,"interface":"input","collection":"work_projects","field":"order"}	{"sort":13,"interface":"input","collection":"work_projects","field":"order"}	\N	\N
55	62	directus_fields	42	{"sort":14,"interface":"input","collection":"work_projects","field":"team"}	{"sort":14,"interface":"input","collection":"work_projects","field":"team"}	\N	\N
56	63	directus_fields	43	{"sort":15,"interface":"input","options":{"placeholder":"https://example.com"},"collection":"work_projects","field":"live_url"}	{"sort":15,"interface":"input","options":{"placeholder":"https://example.com"},"collection":"work_projects","field":"live_url"}	\N	\N
57	64	directus_fields	44	{"sort":16,"interface":"input","collection":"work_projects","field":"case_study_url"}	{"sort":16,"interface":"input","collection":"work_projects","field":"case_study_url"}	\N	\N
58	65	directus_fields	45	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"skills"}	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"skills"}	\N	\N
59	66	directus_collections	skills	{"singleton":false,"icon":"build","note":"Technical skills and technologies","sort_field":"order","collection":"skills"}	{"singleton":false,"icon":"build","note":"Technical skills and technologies","sort_field":"order","collection":"skills"}	\N	\N
60	67	directus_fields	46	{"sort":2,"required":true,"interface":"input","collection":"skills","field":"name"}	{"sort":2,"required":true,"interface":"input","collection":"skills","field":"name"}	\N	\N
61	68	directus_fields	47	{"sort":3,"interface":"select-dropdown","options":{"choices":[{"text":"Frontend","value":"frontend"},{"text":"Backend","value":"backend"},{"text":"DevOps","value":"devops"},{"text":"AI/ML","value":"aiml"},{"text":"Design","value":"design"}]},"collection":"skills","field":"category"}	{"sort":3,"interface":"select-dropdown","options":{"choices":[{"text":"Frontend","value":"frontend"},{"text":"Backend","value":"backend"},{"text":"DevOps","value":"devops"},{"text":"AI/ML","value":"aiml"},{"text":"Design","value":"design"}]},"collection":"skills","field":"category"}	\N	\N
62	69	directus_fields	48	{"sort":4,"interface":"select-dropdown","options":{"choices":[{"text":"Beginner","value":"beginner"},{"text":"Intermediate","value":"intermediate"},{"text":"Expert","value":"expert"}]},"collection":"skills","field":"proficiency"}	{"sort":4,"interface":"select-dropdown","options":{"choices":[{"text":"Beginner","value":"beginner"},{"text":"Intermediate","value":"intermediate"},{"text":"Expert","value":"expert"}]},"collection":"skills","field":"proficiency"}	\N	\N
63	70	directus_fields	49	{"sort":5,"interface":"input","collection":"skills","field":"order"}	{"sort":5,"interface":"input","collection":"skills","field":"order"}	\N	\N
64	71	directus_fields	50	{"sort":6,"interface":"boolean","collection":"skills","field":"featured"}	{"sort":6,"interface":"boolean","collection":"skills","field":"featured"}	\N	\N
65	72	directus_fields	51	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"social_links"}	{"sort":1,"hidden":true,"interface":"numeric","readonly":true,"field":"id","collection":"social_links"}	\N	\N
66	73	directus_collections	social_links	{"singleton":false,"icon":"link","note":"Social media and contact links","sort_field":"order","collection":"social_links"}	{"singleton":false,"icon":"link","note":"Social media and contact links","sort_field":"order","collection":"social_links"}	\N	\N
67	74	directus_fields	52	{"sort":2,"required":true,"interface":"input","collection":"social_links","field":"name"}	{"sort":2,"required":true,"interface":"input","collection":"social_links","field":"name"}	\N	\N
68	75	directus_fields	53	{"sort":3,"required":true,"interface":"input","collection":"social_links","field":"handle"}	{"sort":3,"required":true,"interface":"input","collection":"social_links","field":"handle"}	\N	\N
69	76	directus_fields	54	{"sort":4,"required":true,"interface":"input","collection":"social_links","field":"url"}	{"sort":4,"required":true,"interface":"input","collection":"social_links","field":"url"}	\N	\N
70	77	directus_fields	55	{"sort":5,"interface":"select-dropdown","options":{"choices":[{"text":"GitHub","value":"github"},{"text":"LinkedIn","value":"linkedin"},{"text":"Twitter","value":"twitter"},{"text":"Email","value":"email"},{"text":"Website","value":"website"}]},"collection":"social_links","field":"icon"}	{"sort":5,"interface":"select-dropdown","options":{"choices":[{"text":"GitHub","value":"github"},{"text":"LinkedIn","value":"linkedin"},{"text":"Twitter","value":"twitter"},{"text":"Email","value":"email"},{"text":"Website","value":"website"}]},"collection":"social_links","field":"icon"}	\N	\N
71	78	directus_fields	56	{"sort":6,"interface":"input","collection":"social_links","field":"order"}	{"sort":6,"interface":"input","collection":"social_links","field":"order"}	\N	\N
72	79	directus_fields	57	{"sort":7,"interface":"boolean","collection":"social_links","field":"visible"}	{"sort":7,"interface":"boolean","collection":"social_links","field":"visible"}	\N	\N
73	80	profile	1	{"full_name":"John Chen","first_name":"John","last_name":"Chen","title":"Creative Software Engineer","description":"Building AI-powered applications and fostering innovation through community. Specializing in rapid prototyping, LLM integration, and full-stack development.","email":"john.hk.chen@gmail.com","location":"San Francisco, CA","portfolio_year":"2025","availability":true,"availability_text":"Open to work — AI/ML, Full Stack, Developer Relations","current_role_title":"Community Builder & AI Engineer","current_role_company":"Independent","current_role_duration":"2022 — Present","work_section_title":"Selected Work","work_section_date_range":"2018 — 2025","connect_title":"Let's Connect","connect_description":"Always interested in new opportunities, collaborations, and conversations about AI, developer tools, and community building. Available for full-time roles, contract work, and technical consulting.","footer_copyright":"John Chen","footer_attribution":"Built with Astro, Hono, Directus & Claude Code","footer_year":"2025"}	{"full_name":"John Chen","first_name":"John","last_name":"Chen","title":"Creative Software Engineer","description":"Building AI-powered applications and fostering innovation through community. Specializing in rapid prototyping, LLM integration, and full-stack development.","email":"john.hk.chen@gmail.com","location":"San Francisco, CA","portfolio_year":"2025","availability":true,"availability_text":"Open to work — AI/ML, Full Stack, Developer Relations","current_role_title":"Community Builder & AI Engineer","current_role_company":"Independent","current_role_duration":"2022 — Present","work_section_title":"Selected Work","work_section_date_range":"2018 — 2025","connect_title":"Let's Connect","connect_description":"Always interested in new opportunities, collaborations, and conversations about AI, developer tools, and community building. Available for full-time roles, contract work, and technical consulting.","footer_copyright":"John Chen","footer_attribution":"Built with Astro, Hono, Directus & Claude Code","footer_year":"2025"}	\N	\N
74	81	work_projects	1	{"title":"My Little Soda - Autonomous Coding Agent","slug":"my-little-soda","company":"Open Source","role":"Creator & Maintainer","year":"2024","duration":"Ongoing","description":"GitHub Issues-driven autonomous coding tool that uses LLMs to automatically implement features and fix bugs.","content":"## Overview\\n\\nBuilt an autonomous coding agent that monitors GitHub Issues and automatically generates pull requests with working code implementations.\\n\\n## Technical Implementation\\n- Integrates with GitHub API for issue tracking\\n- Uses Claude/GPT for code generation\\n- Implements automated testing and validation\\n- Handles PR creation and code review workflows\\n\\n## Impact\\n- Demonstrates practical agent architecture patterns\\n- Reduces time from issue creation to implementation\\n- Open source tool for developer productivity","technologies":["Python","GitHub API","Claude","GPT","Autonomous Agents"],"featured":true,"order":1,"status":"published","live_url":"https://github.com/johnhkchen/my-little-soda"}	{"title":"My Little Soda - Autonomous Coding Agent","slug":"my-little-soda","company":"Open Source","role":"Creator & Maintainer","year":"2024","duration":"Ongoing","description":"GitHub Issues-driven autonomous coding tool that uses LLMs to automatically implement features and fix bugs.","content":"## Overview\\n\\nBuilt an autonomous coding agent that monitors GitHub Issues and automatically generates pull requests with working code implementations.\\n\\n## Technical Implementation\\n- Integrates with GitHub API for issue tracking\\n- Uses Claude/GPT for code generation\\n- Implements automated testing and validation\\n- Handles PR creation and code review workflows\\n\\n## Impact\\n- Demonstrates practical agent architecture patterns\\n- Reduces time from issue creation to implementation\\n- Open source tool for developer productivity","technologies":["Python","GitHub API","Claude","GPT","Autonomous Agents"],"featured":true,"order":1,"status":"published","live_url":"https://github.com/johnhkchen/my-little-soda"}	\N	\N
106	114	directus_permissions	2	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":null,"validation":null,"fields":["*"],"presets":null,"collection":"profile","action":"read"}	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":null,"validation":null,"fields":["*"],"presets":null,"collection":"profile","action":"read"}	\N	\N
146	172	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:29:27.663Z","title":"From v0.dev Template to Production: A Technical Deep-Dive","published":true,"content":"# From v0.dev Template to Production: A Technical Deep-Dive\\n\\nMost tutorials stop at \\"here's the template.\\" This shows what comes after: integrating a CMS, building a type-safe API, and deploying with Docker.\\n\\n## The Challenge: Static → Dynamic\\n\\nv0.dev delivers hardcoded UI components:\\n\\n```tsx\\n// Before\\nconst projects = [\\n  { title: \\"Project 1\\", description: \\"...\\" }\\n]\\n```\\n\\nThe goal: Replace with a CMS so content updates don't require code changes:\\n\\n```tsx\\n// After\\nconst projects = await api.getWorkProjects()\\n```\\n\\n## Architecture Decisions\\n\\n### Astro over Next.js\\n\\nContent-first sites don't need React's runtime. Astro ships zero JavaScript by default and builds faster.\\n\\n### Hono over Express\\n\\nHono: 12KB. Express: 200KB+. Better TypeScript DX with type-safe routing:\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')\\n  const project = await getWorkProject(slug)\\n  if (!project) return c.json({ error: 'Not found' }, 404)\\n  return c.json({ data: project })\\n})\\n```\\n\\n### Directus over Strapi/Payload\\n\\nBest admin UI. PostgreSQL-backed. TypeScript SDK with auto-generated types.\\n\\n### Docker Compose\\n\\nIdentical dev/prod environments:\\n\\n```yaml\\nservices:\\n  api:\\n    build: ./api\\n    expose: [\\"3000\\"]\\n    healthcheck:\\n      test: [\\"CMD\\", \\"node\\", \\"-e\\", \\"require('http').get(...)\\"]\\n      interval: 30s\\n\\n  frontend:\\n    build: ./frontend\\n    environment:\\n      API_URL: http://astro-hono-api:3000\\n    depends_on:\\n      api:\\n        condition: service_healthy\\n```\\n\\n### Cloudflare Tunnels\\n\\nNo port forwarding. No firewall config. Free HTTPS. DDoS protection included:\\n\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\n## Implementation\\n\\n### 1. Directus Schema\\n\\n```typescript\\n// api/src/lib/directus.ts\\ninterface WorkProject {\\n  id: number\\n  slug: string              // SEO-friendly URLs\\n  title: string\\n  company: string\\n  role: string\\n  year: string\\n  description: string\\n  content?: string          // Markdown for case studies\\n  technologies: string[]\\n  featured: boolean         // Show on homepage\\n  order?: number            // Manual curation\\n  category?: string         // employment | hackathon | research\\n}\\n```\\n\\n### 2. Type-Safe API Layer\\n\\n```typescript\\n// api/src/lib/directus.ts\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\ninterface Schema {\\n  posts: Post[]\\n  work_projects: WorkProject[]\\n  skills: Skill[]\\n}\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\nexport const getWorkProjects = async () => {\\n  return await directus.request(\\n    readItems('work_projects', {\\n      filter: { status: { _eq: 'published' } },\\n      sort: ['order'],\\n      limit: -1\\n    })\\n  )\\n}\\n```\\n\\nTypeScript knows the data shape at every step. Schema changes surface as compile errors immediately.\\n\\n### 3. Frontend API Client\\n\\n```typescript\\n// frontend/src/lib/api.ts\\nconst API_BASE_URL = import.meta.env.API_URL || 'http://astro-hono-api:3000'\\n\\nexport const api = {\\n  async getWorkProject(slug: string): Promise<WorkProjectResponse> {\\n    const response = await fetch(\\n      `${API_BASE_URL}/api/work-projects/${encodeURIComponent(slug)}`\\n    )\\n    if (!response.ok) throw new Error('Failed to fetch')\\n    return response.json()\\n  }\\n}\\n```\\n\\nEnvironment variables switch between Docker internal network (dev) and Cloudflare Tunnel (prod).\\n\\n### 4. Content Adapter Pattern\\n\\nAstro expects content collections. Directus provides an API. The adapter bridges them:\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  const project = response.data\\n  return {\\n    slug: project.slug,\\n    data: {\\n      title: project.title,\\n      company: project.company,\\n      technologies: project.technologies || [],\\n      content: project.content\\n    }\\n  }\\n}\\n```\\n\\nThis means:\\n- Astro pages unchanged\\n- CMS swappable (rewrite adapter only)\\n- Type safety preserved\\n\\n### 5. Dynamic Routes\\n\\n```astro\\n---\\n// pages/work/[slug].astro\\nimport { getWorkProject } from '../../content'\\n\\nconst { slug } = Astro.params\\nconst project = await getWorkProject(slug)\\nif (!project) return Astro.redirect('/404')\\n---\\n\\n<Layout title={project.data.title}>\\n  <h1>{project.data.title}</h1>\\n  <p>{project.data.role} @ {project.data.company}</p>\\n\\n  {project.data.technologies.map(tech => (\\n    <Tag text={tech} />\\n  ))}\\n</Layout>\\n```\\n\\nFlow: **URL → Astro → Adapter → API → Directus → PostgreSQL**\\n\\nEach layer adds type safety. Misspelled fields fail at build time.\\n\\n## The Type Safety Chain\\n\\nTypes flow through every layer:\\n\\n1. Directus Schema → Database collections\\n2. API Interfaces → Mirror Directus schema\\n3. Frontend Interfaces → Match API responses\\n4. Astro Components → Typed data with autocomplete\\n\\nAdding a field:\\n1. Add `github_url` in Directus UI\\n2. Update `WorkProject` in `api/src/lib/directus.ts`\\n3. Update `WorkProject` in `frontend/src/lib/api.ts`\\n4. TypeScript now knows `project.data.github_url`\\n\\nForget step 2 or 3? Build fails.\\n\\n## Lessons Learned\\n\\n### What Worked\\n\\n**Type safety caught bugs early.** No \\"undefined is not an object\\" in production.\\n\\n**Directus admin UI.** Non-developers can update content without code changes.\\n\\n**Docker Compose.** Works locally = works in production.\\n\\n**Content adapter pattern.** Swap CMS by rewriting one file.\\n\\n### What Was Hard\\n\\n**TypeScript interfaces across layers.** Initially defined separately in each layer. Solution: Generate types from Directus schema once.\\n\\n**Docker networking.** Services couldn't reach each other. Solution: Same Docker network. Healthchecks prevent race conditions.\\n\\n**Directus schema design.** Three iterations. Too normalized (too many joins), too flat (duplicated data), finally balanced.\\n\\n### What I'd Do Differently\\n\\n**Start with schema design, not UI.** Built components first, then tried to fit Directus around them. Should be reversed.\\n\\n**Use Directus SDK from start.** Initially wrote raw HTTP. SDK handles auth, filtering, pagination automatically.\\n\\n**Set up Cloudflare Tunnel earlier.** Wasted time on nginx config.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Traefik, Cloudflare Tunnels\\n\\n**Performance:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse: 95+\\n\\n**Workflow:**\\n1. Edit in Directus\\n2. Changes appear instantly (SSR)\\n3. No build, no deployment\\n\\n## Key Files\\n\\n- `api/src/index.ts` - Hono routes\\n- `api/src/lib/directus.ts` - Type-safe queries\\n- `frontend/src/lib/api.ts` - Fetch wrappers\\n- `frontend/src/content/index.ts` - Content adapter\\n- `frontend/src/pages/work/[slug].astro` - Dynamic routes\\n- `compose.yaml` - Docker orchestration\\n\\n---\\n\\n**Template:** Felix Macaspac's v0.dev minimalist portfolio (v0.app/templates/minimalist-portfolio-1DPeR9dunMc)\\n"}	{"content":"# From v0.dev Template to Production: A Technical Deep-Dive\\n\\nMost tutorials stop at \\"here's the template.\\" This shows what comes after: integrating a CMS, building a type-safe API, and deploying with Docker.\\n\\n## The Challenge: Static → Dynamic\\n\\nv0.dev delivers hardcoded UI components:\\n\\n```tsx\\n// Before\\nconst projects = [\\n  { title: \\"Project 1\\", description: \\"...\\" }\\n]\\n```\\n\\nThe goal: Replace with a CMS so content updates don't require code changes:\\n\\n```tsx\\n// After\\nconst projects = await api.getWorkProjects()\\n```\\n\\n## Architecture Decisions\\n\\n### Astro over Next.js\\n\\nContent-first sites don't need React's runtime. Astro ships zero JavaScript by default and builds faster.\\n\\n### Hono over Express\\n\\nHono: 12KB. Express: 200KB+. Better TypeScript DX with type-safe routing:\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')\\n  const project = await getWorkProject(slug)\\n  if (!project) return c.json({ error: 'Not found' }, 404)\\n  return c.json({ data: project })\\n})\\n```\\n\\n### Directus over Strapi/Payload\\n\\nBest admin UI. PostgreSQL-backed. TypeScript SDK with auto-generated types.\\n\\n### Docker Compose\\n\\nIdentical dev/prod environments:\\n\\n```yaml\\nservices:\\n  api:\\n    build: ./api\\n    expose: [\\"3000\\"]\\n    healthcheck:\\n      test: [\\"CMD\\", \\"node\\", \\"-e\\", \\"require('http').get(...)\\"]\\n      interval: 30s\\n\\n  frontend:\\n    build: ./frontend\\n    environment:\\n      API_URL: http://astro-hono-api:3000\\n    depends_on:\\n      api:\\n        condition: service_healthy\\n```\\n\\n### Cloudflare Tunnels\\n\\nNo port forwarding. No firewall config. Free HTTPS. DDoS protection included:\\n\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\n## Implementation\\n\\n### 1. Directus Schema\\n\\n```typescript\\n// api/src/lib/directus.ts\\ninterface WorkProject {\\n  id: number\\n  slug: string              // SEO-friendly URLs\\n  title: string\\n  company: string\\n  role: string\\n  year: string\\n  description: string\\n  content?: string          // Markdown for case studies\\n  technologies: string[]\\n  featured: boolean         // Show on homepage\\n  order?: number            // Manual curation\\n  category?: string         // employment | hackathon | research\\n}\\n```\\n\\n### 2. Type-Safe API Layer\\n\\n```typescript\\n// api/src/lib/directus.ts\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\ninterface Schema {\\n  posts: Post[]\\n  work_projects: WorkProject[]\\n  skills: Skill[]\\n}\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\nexport const getWorkProjects = async () => {\\n  return await directus.request(\\n    readItems('work_projects', {\\n      filter: { status: { _eq: 'published' } },\\n      sort: ['order'],\\n      limit: -1\\n    })\\n  )\\n}\\n```\\n\\nTypeScript knows the data shape at every step. Schema changes surface as compile errors immediately.\\n\\n### 3. Frontend API Client\\n\\n```typescript\\n// frontend/src/lib/api.ts\\nconst API_BASE_URL = import.meta.env.API_URL || 'http://astro-hono-api:3000'\\n\\nexport const api = {\\n  async getWorkProject(slug: string): Promise<WorkProjectResponse> {\\n    const response = await fetch(\\n      `${API_BASE_URL}/api/work-projects/${encodeURIComponent(slug)}`\\n    )\\n    if (!response.ok) throw new Error('Failed to fetch')\\n    return response.json()\\n  }\\n}\\n```\\n\\nEnvironment variables switch between Docker internal network (dev) and Cloudflare Tunnel (prod).\\n\\n### 4. Content Adapter Pattern\\n\\nAstro expects content collections. Directus provides an API. The adapter bridges them:\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  const project = response.data\\n  return {\\n    slug: project.slug,\\n    data: {\\n      title: project.title,\\n      company: project.company,\\n      technologies: project.technologies || [],\\n      content: project.content\\n    }\\n  }\\n}\\n```\\n\\nThis means:\\n- Astro pages unchanged\\n- CMS swappable (rewrite adapter only)\\n- Type safety preserved\\n\\n### 5. Dynamic Routes\\n\\n```astro\\n---\\n// pages/work/[slug].astro\\nimport { getWorkProject } from '../../content'\\n\\nconst { slug } = Astro.params\\nconst project = await getWorkProject(slug)\\nif (!project) return Astro.redirect('/404')\\n---\\n\\n<Layout title={project.data.title}>\\n  <h1>{project.data.title}</h1>\\n  <p>{project.data.role} @ {project.data.company}</p>\\n\\n  {project.data.technologies.map(tech => (\\n    <Tag text={tech} />\\n  ))}\\n</Layout>\\n```\\n\\nFlow: **URL → Astro → Adapter → API → Directus → PostgreSQL**\\n\\nEach layer adds type safety. Misspelled fields fail at build time.\\n\\n## The Type Safety Chain\\n\\nTypes flow through every layer:\\n\\n1. Directus Schema → Database collections\\n2. API Interfaces → Mirror Directus schema\\n3. Frontend Interfaces → Match API responses\\n4. Astro Components → Typed data with autocomplete\\n\\nAdding a field:\\n1. Add `github_url` in Directus UI\\n2. Update `WorkProject` in `api/src/lib/directus.ts`\\n3. Update `WorkProject` in `frontend/src/lib/api.ts`\\n4. TypeScript now knows `project.data.github_url`\\n\\nForget step 2 or 3? Build fails.\\n\\n## Lessons Learned\\n\\n### What Worked\\n\\n**Type safety caught bugs early.** No \\"undefined is not an object\\" in production.\\n\\n**Directus admin UI.** Non-developers can update content without code changes.\\n\\n**Docker Compose.** Works locally = works in production.\\n\\n**Content adapter pattern.** Swap CMS by rewriting one file.\\n\\n### What Was Hard\\n\\n**TypeScript interfaces across layers.** Initially defined separately in each layer. Solution: Generate types from Directus schema once.\\n\\n**Docker networking.** Services couldn't reach each other. Solution: Same Docker network. Healthchecks prevent race conditions.\\n\\n**Directus schema design.** Three iterations. Too normalized (too many joins), too flat (duplicated data), finally balanced.\\n\\n### What I'd Do Differently\\n\\n**Start with schema design, not UI.** Built components first, then tried to fit Directus around them. Should be reversed.\\n\\n**Use Directus SDK from start.** Initially wrote raw HTTP. SDK handles auth, filtering, pagination automatically.\\n\\n**Set up Cloudflare Tunnel earlier.** Wasted time on nginx config.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Traefik, Cloudflare Tunnels\\n\\n**Performance:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse: 95+\\n\\n**Workflow:**\\n1. Edit in Directus\\n2. Changes appear instantly (SSR)\\n3. No build, no deployment\\n\\n## Key Files\\n\\n- `api/src/index.ts` - Hono routes\\n- `api/src/lib/directus.ts` - Type-safe queries\\n- `frontend/src/lib/api.ts` - Fetch wrappers\\n- `frontend/src/content/index.ts` - Content adapter\\n- `frontend/src/pages/work/[slug].astro` - Dynamic routes\\n- `compose.yaml` - Docker orchestration\\n\\n---\\n\\n**Template:** Felix Macaspac's v0.dev minimalist portfolio (v0.app/templates/minimalist-portfolio-1DPeR9dunMc)\\n","date_updated":"2025-10-14T06:29:27.663Z"}	\N	\N
153	180	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:48:20.338Z","title":"v0 to Production","published":true,"content":"# Building Production Sites with AI: Why Curation Beats Automation\\n\\nOne day of prompting. Production-ready portfolio. But not because AI is magic—because I knew what to ask for.\\n\\n## The Setup\\n\\n**What I saw:** v0.dev templates at an AWS event. Beautiful. Locked to Vercel's framework.\\n\\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\\n\\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\\n\\n**Why it worked:** Curation and taste. Not because AI figured it out.\\n\\n## What AI Gives You Without Direction\\n\\nLeft to its own devices, Claude Code suggests:\\n\\n**The default stack:**\\n- Express (because it's popular)\\n- Basic JavaScript (because it's simple)\\n- Hardcoded data (because it works)\\n- Generic placeholders everywhere\\n\\n**What you get:** Something that runs. Nothing you'd ship.\\n\\nThis is the trap: AI coding tools *work*, but they optimize for \\"runs quickly\\" not \\"production-grade.\\"\\n\\n## What Changes with Curation\\n\\nWhen you know what exists, you can prompt differently.\\n\\n**Without curation:**\\n> \\"Build me a portfolio site\\"\\n\\nResult: Next.js with hardcoded content. Generic. Forgettable.\\n\\n**With curation:**\\n> \\"I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe.\\"\\n\\nResult: Production architecture in a day.\\n\\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\\n\\n## Where I Actually Learned\\n\\n### Tech Events\\n\\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: \\"Great UI, wrong stack for my needs.\\"\\n\\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\\n\\n### The Internet Annals\\n\\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\\n\\nNot tutorials. Real people discussing real trade-offs.\\n\\n### Small Experiments with Claude Code\\n\\nBuilding throwaway projects:\\n- \\"Show me how Directus works\\"\\n- \\"What's the Hono API surface look like?\\"\\n- \\"How does Astro handle dynamic routes?\\"\\n\\nRudimentary understanding. Just enough to know what's possible.\\n\\n## The Moment of Synthesis\\n\\nv0.dev templates are beautiful. But I wanted:\\n- Astro (better for content than Next.js)\\n- Self-hosted (not Vercel-locked)\\n- Directus (better admin UI than competitors)\\n- Hono (lighter than Express)\\n\\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\\n\\n## What One Day of Prompting Looks Like\\n\\n### Morning: The Conversion\\n\\n**Me:** \\"This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework.\\"\\n\\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\\n\\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\\n\\n### Afternoon: The Integration\\n\\n**Me:** \\"Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API.\\"\\n\\n**Claude Code:** Implements the adapter. Type-safe throughout.\\n\\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\\n\\n### Evening: The Deployment\\n\\n**Me:** \\"Docker Compose. Frontend, API, Directus. Healthchecks so they start in order.\\"\\n\\n**Claude Code:** Generates docker-compose.yml. We debug networking.\\n\\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\\n\\n## The LLM-Driven Issue Loop\\n\\nThis is where Sonnet 4.5 shines:\\n\\n**Pattern:**\\n1. Build a feature\\n2. Test it\\n3. Hit an error\\n4. Paste error to Claude Code\\n5. It suggests fix\\n6. Repeat\\n\\n**Example:**\\n- Docker services can't reach each other\\n- Paste error logs\\n- \\"Add them all to the same network\\"\\n- Works\\n\\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\\n\\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\\n\\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\\n\\n## What Curation Actually Means\\n\\n### 1. Knowing What Exists\\n\\nI can't ask for Hono if I don't know it exists. I learned it from:\\n- Tech event hallway conversation\\n- Seeing it on a \\"lightweight Node frameworks\\" list\\n- Building a throwaway API to understand it\\n\\n**The work:** Self-directed learning. Tech events. Experimentation.\\n\\n### 2. Understanding Trade-offs\\n\\nWhen Claude Code suggests Express, I know to push back: \\"What about Hono?\\"\\n\\nWhen it suggests Strapi, I counter with: \\"Directus has a better admin UI.\\"\\n\\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\\n\\n### 3. Recognizing Good Architecture\\n\\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\\n- Separates concerns\\n- Keeps Astro pages clean\\n- Makes CMS swappable\\n\\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\\n\\n### 4. Directing, Not Just Accepting\\n\\nDefault: \\"Build me X\\" → AI chooses everything\\n\\nCurated: \\"I want A, B, C integrated. Show me how\\" → You choose, AI implements\\n\\n**The difference:** Agency. You're in control.\\n\\n## Why This Moment Matters\\n\\n### The Timing\\n\\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\\n\\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\\n\\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\\n\\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\\n\\n### What Makes This Reproducible\\n\\nNot \\"use these exact tools.\\"\\n\\nBut: **Build your curation muscle, then execute with AI.**\\n\\n**How to build curation:**\\n1. Go to tech events (see tools demoed, hear hallway chatter)\\n2. Dig through forums (understand why people choose X over Y)\\n3. Build small experiments (gain rudimentary understanding)\\n4. Develop taste (know when \\"good enough\\" vs \\"production-grade\\")\\n\\n**Then when Sonnet 4.5 (or better) exists:**\\n- You can name what you want\\n- AI handles implementation details\\n- One day of focused work = production site\\n\\n## The Honest Comparison\\n\\n### Without Curation\\n**Prompt:** \\"Build me a portfolio site\\"\\n\\n**Result:** Express + basic JS + placeholders\\n\\n**Time to production:** Weeks of refactoring to make it real\\n\\n### With Curation\\n**Prompt:** \\"Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment.\\"\\n\\n**Result:** Production-grade architecture from day one\\n\\n**Time to production:** One day of focused prompting\\n\\n**The difference:** I did the learning beforehand. AI does the implementation now.\\n\\n## What You Actually Need to Learn\\n\\n**Not from AI:**\\n- What tools exist in the ecosystem\\n- Why people choose specific tools\\n- Trade-offs between options\\n- What \\"production-grade\\" looks like\\n\\n**From AI:**\\n- How to integrate specific tools\\n- Configuration syntax\\n- Implementation patterns\\n- Fixing specific errors\\n\\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\\n\\n## The Pattern\\n\\n**Phase 1: Self-Directed Learning**\\n- Attend tech events\\n- Read forums and GitHub issues\\n- Experiment with tools in isolation\\n- Develop opinions about trade-offs\\n\\n**Phase 2: Small Experiments**\\n- Build throwaway projects with Claude Code\\n- Gain rudimentary understanding\\n- Learn what's possible, what's hard\\n\\n**Phase 3: Recognition**\\n- \\"I know what I want to build\\"\\n- \\"I know which tools fit together\\"\\n- \\"I can direct an AI toward this vision\\"\\n\\n**Phase 4: Execution**\\n- One day of focused prompting\\n- LLM-driven issue loop (error → fix → repeat)\\n- Production-grade result\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Timeline:**\\n- Months of learning (events, experiments, forums)\\n- One day of building (prompting + iteration)\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\\n\\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\\n\\n## The Real Unlock\\n\\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\\n\\n**2025:** You need to know what to build and why. AI builds it for you.\\n\\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\\n\\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\\n\\n**When AI amplifies it:** When you can say \\"I want A, B, C integrated\\" and the AI handles implementation.\\n\\nThe tools haven't changed. The leverage has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\\n"}	{"title":"v0 to Production","date_updated":"2025-10-14T06:48:20.338Z"}	\N	\N
75	82	work_projects	2	{"title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Co-Founder & Treasurer","year":"2022-2024","duration":"2 years","description":"Founded and led CS Club, helping students transfer to top universities including UC Berkeley. Built community site and organized 100+ tech events.","content":"## Overview\\n\\nCo-founded and managed CS Club at CCSF, creating a thriving community that helped students succeed in tech careers.\\n\\n## Achievements\\n- **Student Success**: 2 consecutive years of students transferring to UC Berkeley\\n- **Events**: Organized 100+ hackathons, workshops, and tech meetups\\n- **Education**: Introduced students to Astro, helping them build professional portfolios\\n- **Community Site**: Built https://ccsf-cs.club for resources and announcements\\n\\n## Impact\\n- Mentored first-time hackathon participants\\n- Connected students with SF tech community\\n- Created pathways for non-traditional students into tech careers","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":2,"status":"published","live_url":"https://ccsf-cs.club"}	{"title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Co-Founder & Treasurer","year":"2022-2024","duration":"2 years","description":"Founded and led CS Club, helping students transfer to top universities including UC Berkeley. Built community site and organized 100+ tech events.","content":"## Overview\\n\\nCo-founded and managed CS Club at CCSF, creating a thriving community that helped students succeed in tech careers.\\n\\n## Achievements\\n- **Student Success**: 2 consecutive years of students transferring to UC Berkeley\\n- **Events**: Organized 100+ hackathons, workshops, and tech meetups\\n- **Education**: Introduced students to Astro, helping them build professional portfolios\\n- **Community Site**: Built https://ccsf-cs.club for resources and announcements\\n\\n## Impact\\n- Mentored first-time hackathon participants\\n- Connected students with SF tech community\\n- Created pathways for non-traditional students into tech careers","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":2,"status":"published","live_url":"https://ccsf-cs.club"}	\N	\N
76	83	work_projects	3	{"title":"Tech Event Analyzer - Hackathon Project","slug":"tech-event-analyzer","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"Discovered Lu.ma pagination API vulnerability and built analyzer to identify which tech companies consistently provide food at events. Found Cloudflare, AWS, and GitHub as top sponsors.","content":"## Problem\\n\\nTech event attendees need to know which events are worth attending beyond just the topic.\\n\\n## Solution\\n\\nBuilt a scraper and analyzer that:\\n- Discovered and utilized undocumented Lu.ma pagination API\\n- Extracted event data including sponsors and amenities\\n- Identified patterns in sponsor behavior\\n- Ranked companies by event quality metrics\\n\\n## Key Findings\\n- Cloudflare, AWS, and GitHub consistently budget for attendee food\\n- Correlation between food quality and event engagement\\n- Useful for event planning and attendee decision-making\\n\\n## Technologies\\n- API reverse engineering\\n- Data analysis and visualization\\n- Pattern recognition","technologies":["Python","API Scraping","Data Analysis","Lu.ma"],"featured":true,"order":3,"status":"published"}	{"title":"Tech Event Analyzer - Hackathon Project","slug":"tech-event-analyzer","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"Discovered Lu.ma pagination API vulnerability and built analyzer to identify which tech companies consistently provide food at events. Found Cloudflare, AWS, and GitHub as top sponsors.","content":"## Problem\\n\\nTech event attendees need to know which events are worth attending beyond just the topic.\\n\\n## Solution\\n\\nBuilt a scraper and analyzer that:\\n- Discovered and utilized undocumented Lu.ma pagination API\\n- Extracted event data including sponsors and amenities\\n- Identified patterns in sponsor behavior\\n- Ranked companies by event quality metrics\\n\\n## Key Findings\\n- Cloudflare, AWS, and GitHub consistently budget for attendee food\\n- Correlation between food quality and event engagement\\n- Useful for event planning and attendee decision-making\\n\\n## Technologies\\n- API reverse engineering\\n- Data analysis and visualization\\n- Pattern recognition","technologies":["Python","API Scraping","Data Analysis","Lu.ma"],"featured":true,"order":3,"status":"published"}	\N	\N
77	84	work_projects	4	{"title":"SF Legacy Business Registry - Civic Tech","slug":"sf-legacy-business-registry","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"8 hours","description":"Built PDF-to-structured-data pipeline using LlamaParse to transform San Francisco legacy business applications into an engaging, searchable database.","content":"## Problem\\n\\nSan Francisco's legacy business data was trapped in PDF application forms, making it difficult to discover and explore the city's historic businesses.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Used LlamaParse to extract structured data from PDF applications\\n- Cleaned and normalized business information\\n- Built searchable database with rich metadata\\n\\n### User Experience\\n- Created engaging visual interface for browsing businesses\\n- Added filtering by neighborhood, business type, and year established\\n- Implemented search functionality\\n\\n## Impact\\n- Made civic data accessible and useful\\n- Demonstrated practical LLM applications for document processing\\n- Created reusable pipeline for similar civic tech projects\\n\\n## Tech Stack\\n- LlamaParse for PDF extraction\\n- Vector search for semantic queries\\n- Modern web framework for UI","technologies":["LlamaParse","PDF Processing","Civic Tech","Vector Search","Full Stack"],"featured":true,"order":4,"status":"published"}	{"title":"SF Legacy Business Registry - Civic Tech","slug":"sf-legacy-business-registry","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"8 hours","description":"Built PDF-to-structured-data pipeline using LlamaParse to transform San Francisco legacy business applications into an engaging, searchable database.","content":"## Problem\\n\\nSan Francisco's legacy business data was trapped in PDF application forms, making it difficult to discover and explore the city's historic businesses.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Used LlamaParse to extract structured data from PDF applications\\n- Cleaned and normalized business information\\n- Built searchable database with rich metadata\\n\\n### User Experience\\n- Created engaging visual interface for browsing businesses\\n- Added filtering by neighborhood, business type, and year established\\n- Implemented search functionality\\n\\n## Impact\\n- Made civic data accessible and useful\\n- Demonstrated practical LLM applications for document processing\\n- Created reusable pipeline for similar civic tech projects\\n\\n## Tech Stack\\n- LlamaParse for PDF extraction\\n- Vector search for semantic queries\\n- Modern web framework for UI","technologies":["LlamaParse","PDF Processing","Civic Tech","Vector Search","Full Stack"],"featured":true,"order":4,"status":"published"}	\N	\N
78	85	work_projects	5	{"title":"Piper - STEM Learning Platform","slug":"piper","company":"Piper, Inc.","role":"Software Engineer","year":"2018-2021","duration":"3 years 5 months","description":"Shipped expansion pack that increased customer LTV by 25%. Built analytics infrastructure, FERPA-compliant survey system, and technical blog content.","content":"## Role & Responsibilities\\n\\nFull-stack engineer on Python-based STEM learning game for K-12 education.\\n\\n## Key Achievements\\n\\n### Product Development\\n- **Expansion Pack**: Shipped major release increasing customer LTV by 25%\\n- **Map Converter**: Built forward-compatible Python tool enabling new visual and mechanical game features\\n- **Technical Writing**: Created blog series exploring CS and EE concepts through DIY projects\\n\\n### Infrastructure & Analytics\\n- **Analytics Dashboard**: Set up SQL and Amplitude for marketing, QA, and dev-ops intelligence\\n- **Survey System**: Developed FERPA-compliant web service using JavaScript, Google Apps Engine, and Firebase\\n\\n## Impact\\n- Directly contributed to revenue growth\\n- Improved development workflow and tooling\\n- Enhanced data-driven decision making","technologies":["Python","JavaScript","SQL","Firebase","Google Apps Engine","Amplitude","Game Development"],"featured":true,"order":5,"status":"published"}	{"title":"Piper - STEM Learning Platform","slug":"piper","company":"Piper, Inc.","role":"Software Engineer","year":"2018-2021","duration":"3 years 5 months","description":"Shipped expansion pack that increased customer LTV by 25%. Built analytics infrastructure, FERPA-compliant survey system, and technical blog content.","content":"## Role & Responsibilities\\n\\nFull-stack engineer on Python-based STEM learning game for K-12 education.\\n\\n## Key Achievements\\n\\n### Product Development\\n- **Expansion Pack**: Shipped major release increasing customer LTV by 25%\\n- **Map Converter**: Built forward-compatible Python tool enabling new visual and mechanical game features\\n- **Technical Writing**: Created blog series exploring CS and EE concepts through DIY projects\\n\\n### Infrastructure & Analytics\\n- **Analytics Dashboard**: Set up SQL and Amplitude for marketing, QA, and dev-ops intelligence\\n- **Survey System**: Developed FERPA-compliant web service using JavaScript, Google Apps Engine, and Firebase\\n\\n## Impact\\n- Directly contributed to revenue growth\\n- Improved development workflow and tooling\\n- Enhanced data-driven decision making","technologies":["Python","JavaScript","SQL","Firebase","Google Apps Engine","Amplitude","Game Development"],"featured":true,"order":5,"status":"published"}	\N	\N
79	86	work_projects	6	{"title":"IdeaWall - HCI Research","slug":"ideawall-research","company":"UC Davis Visualization Lab","role":"Research Assistant","year":"2015-2016","duration":"1 year 2 months","description":"Co-authored ACM CSCW paper on AI-augmented creative collaboration. Built real-time system extracting discussion insights and providing combinatorial visual stimuli.","content":"## Research Project\\n\\n**Published**: ACM Conference on Computer Supported Cooperative Work and Social Computing (CSCW '17)\\n\\n## Overview\\n\\nDeveloped IdeaWall, an intelligent system that augments verbal creative collaboration with real-time visual stimuli.\\n\\n## Technical Implementation\\n- Real-time speech processing and information extraction\\n- Web search integration for contextual materials\\n- Visual display system with three cognitive strategies\\n- User study with 24 participants across 12 groups\\n\\n## Research Contributions\\n- Demonstrated effectiveness of AI-assisted collaboration tools\\n- Validated three cognitive strategies for visual facilitation\\n- Set foundation for future intelligent groupware systems\\n\\n## Skills Developed\\n- Research methodology and user testing\\n- Technical writing for academic publication\\n- Data visualization and analysis\\n- Human-computer interaction design","technologies":["HCI Research","Real-time Processing","User Studies","Data Visualization","Academic Writing"],"featured":true,"order":6,"status":"published","case_study_url":"http://dl.acm.org/citation.cfm?id=2998208"}	{"title":"IdeaWall - HCI Research","slug":"ideawall-research","company":"UC Davis Visualization Lab","role":"Research Assistant","year":"2015-2016","duration":"1 year 2 months","description":"Co-authored ACM CSCW paper on AI-augmented creative collaboration. Built real-time system extracting discussion insights and providing combinatorial visual stimuli.","content":"## Research Project\\n\\n**Published**: ACM Conference on Computer Supported Cooperative Work and Social Computing (CSCW '17)\\n\\n## Overview\\n\\nDeveloped IdeaWall, an intelligent system that augments verbal creative collaboration with real-time visual stimuli.\\n\\n## Technical Implementation\\n- Real-time speech processing and information extraction\\n- Web search integration for contextual materials\\n- Visual display system with three cognitive strategies\\n- User study with 24 participants across 12 groups\\n\\n## Research Contributions\\n- Demonstrated effectiveness of AI-assisted collaboration tools\\n- Validated three cognitive strategies for visual facilitation\\n- Set foundation for future intelligent groupware systems\\n\\n## Skills Developed\\n- Research methodology and user testing\\n- Technical writing for academic publication\\n- Data visualization and analysis\\n- Human-computer interaction design","technologies":["HCI Research","Real-time Processing","User Studies","Data Visualization","Academic Writing"],"featured":true,"order":6,"status":"published","case_study_url":"http://dl.acm.org/citation.cfm?id=2998208"}	\N	\N
80	87	work_projects	7	{"title":"Fitness Planner - Vector Search Application","slug":"fitness-planner","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"AI-powered fitness routine suggester using Weaviate vector database. Transforms user descriptions into personalized workout plans.","content":"## Concept\\n\\nNatural language fitness planning: describe your goals and fitness level, get personalized workout routines.\\n\\n## Technical Implementation\\n\\n### Vector Search\\n- Used Weaviate for semantic workout search\\n- Embedded fitness routines with descriptions\\n- Implemented semantic similarity matching\\n\\n### Example Queries\\n- \\"out of shape 30 year old couch to 5k\\"\\n- \\"strength training for beginners\\"\\n- \\"low impact cardio for seniors\\"\\n\\n### Structured Output\\n- Generated progressive workout plans\\n- Included exercise descriptions and modifications\\n- Suggested timelines and milestones\\n\\n## Learning\\n- Practical vector database implementation\\n- Semantic search for recommendation systems\\n- Rapid prototyping with modern AI tools","technologies":["Weaviate","Vector Search","LLM","Full Stack","RAG"],"featured":false,"order":7,"status":"published"}	{"title":"Fitness Planner - Vector Search Application","slug":"fitness-planner","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"AI-powered fitness routine suggester using Weaviate vector database. Transforms user descriptions into personalized workout plans.","content":"## Concept\\n\\nNatural language fitness planning: describe your goals and fitness level, get personalized workout routines.\\n\\n## Technical Implementation\\n\\n### Vector Search\\n- Used Weaviate for semantic workout search\\n- Embedded fitness routines with descriptions\\n- Implemented semantic similarity matching\\n\\n### Example Queries\\n- \\"out of shape 30 year old couch to 5k\\"\\n- \\"strength training for beginners\\"\\n- \\"low impact cardio for seniors\\"\\n\\n### Structured Output\\n- Generated progressive workout plans\\n- Included exercise descriptions and modifications\\n- Suggested timelines and milestones\\n\\n## Learning\\n- Practical vector database implementation\\n- Semantic search for recommendation systems\\n- Rapid prototyping with modern AI tools","technologies":["Weaviate","Vector Search","LLM","Full Stack","RAG"],"featured":false,"order":7,"status":"published"}	\N	\N
107	115	directus_permissions	3	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":null,"validation":null,"fields":["*"],"presets":null,"collection":"skills","action":"read"}	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":null,"validation":null,"fields":["*"],"presets":null,"collection":"skills","action":"read"}	\N	\N
147	173	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:30:22.528Z","title":"v0 to Production","published":true,"content":"Most tutorials stop at \\"here's the template.\\" This shows what comes after: integrating a CMS, building a type-safe API, and deploying with Docker.\\n\\n## The Challenge: Static → Dynamic\\n\\nv0.dev delivers hardcoded UI components:\\n\\n```tsx\\n// Before\\nconst projects = [\\n  { title: \\"Project 1\\", description: \\"...\\" }\\n]\\n```\\n\\nThe goal: Replace with a CMS so content updates don't require code changes:\\n\\n```tsx\\n// After\\nconst projects = await api.getWorkProjects()\\n```\\n\\n## Architecture Decisions\\n\\n### Astro over Next.js\\n\\nContent-first sites don't need React's runtime. Astro ships zero JavaScript by default and builds faster.\\n\\n### Hono over Express\\n\\nHono: 12KB. Express: 200KB+. Better TypeScript DX with type-safe routing:\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')\\n  const project = await getWorkProject(slug)\\n  if (!project) return c.json({ error: 'Not found' }, 404)\\n  return c.json({ data: project })\\n})\\n```\\n\\n### Directus over Strapi/Payload\\n\\nBest admin UI. PostgreSQL-backed. TypeScript SDK with auto-generated types.\\n\\n### Docker Compose\\n\\nIdentical dev/prod environments:\\n\\n```yaml\\nservices:\\n  api:\\n    build: ./api\\n    expose: [\\"3000\\"]\\n    healthcheck:\\n      test: [\\"CMD\\", \\"node\\", \\"-e\\", \\"require('http').get(...)\\"]\\n      interval: 30s\\n\\n  frontend:\\n    build: ./frontend\\n    environment:\\n      API_URL: http://astro-hono-api:3000\\n    depends_on:\\n      api:\\n        condition: service_healthy\\n```\\n\\n### Cloudflare Tunnels\\n\\nNo port forwarding. No firewall config. Free HTTPS. DDoS protection included:\\n\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\n## Implementation\\n\\n### 1. Directus Schema\\n\\n```typescript\\n// api/src/lib/directus.ts\\ninterface WorkProject {\\n  id: number\\n  slug: string              // SEO-friendly URLs\\n  title: string\\n  company: string\\n  role: string\\n  year: string\\n  description: string\\n  content?: string          // Markdown for case studies\\n  technologies: string[]\\n  featured: boolean         // Show on homepage\\n  order?: number            // Manual curation\\n  category?: string         // employment | hackathon | research\\n}\\n```\\n\\n### 2. Type-Safe API Layer\\n\\n```typescript\\n// api/src/lib/directus.ts\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\ninterface Schema {\\n  posts: Post[]\\n  work_projects: WorkProject[]\\n  skills: Skill[]\\n}\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\nexport const getWorkProjects = async () => {\\n  return await directus.request(\\n    readItems('work_projects', {\\n      filter: { status: { _eq: 'published' } },\\n      sort: ['order'],\\n      limit: -1\\n    })\\n  )\\n}\\n```\\n\\nTypeScript knows the data shape at every step. Schema changes surface as compile errors immediately.\\n\\n### 3. Frontend API Client\\n\\n```typescript\\n// frontend/src/lib/api.ts\\nconst API_BASE_URL = import.meta.env.API_URL || 'http://astro-hono-api:3000'\\n\\nexport const api = {\\n  async getWorkProject(slug: string): Promise<WorkProjectResponse> {\\n    const response = await fetch(\\n      `${API_BASE_URL}/api/work-projects/${encodeURIComponent(slug)}`\\n    )\\n    if (!response.ok) throw new Error('Failed to fetch')\\n    return response.json()\\n  }\\n}\\n```\\n\\nEnvironment variables switch between Docker internal network (dev) and Cloudflare Tunnel (prod).\\n\\n### 4. Content Adapter Pattern\\n\\nAstro expects content collections. Directus provides an API. The adapter bridges them:\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  const project = response.data\\n  return {\\n    slug: project.slug,\\n    data: {\\n      title: project.title,\\n      company: project.company,\\n      technologies: project.technologies || [],\\n      content: project.content\\n    }\\n  }\\n}\\n```\\n\\nThis means:\\n- Astro pages unchanged\\n- CMS swappable (rewrite adapter only)\\n- Type safety preserved\\n\\n### 5. Dynamic Routes\\n\\n```astro\\n---\\n// pages/work/[slug].astro\\nimport { getWorkProject } from '../../content'\\n\\nconst { slug } = Astro.params\\nconst project = await getWorkProject(slug)\\nif (!project) return Astro.redirect('/404')\\n---\\n\\n<Layout title={project.data.title}>\\n  <h1>{project.data.title}</h1>\\n  <p>{project.data.role} @ {project.data.company}</p>\\n\\n  {project.data.technologies.map(tech => (\\n    <Tag text={tech} />\\n  ))}\\n</Layout>\\n```\\n\\nFlow: **URL → Astro → Adapter → API → Directus → PostgreSQL**\\n\\nEach layer adds type safety. Misspelled fields fail at build time.\\n\\n## The Type Safety Chain\\n\\nTypes flow through every layer:\\n\\n1. Directus Schema → Database collections\\n2. API Interfaces → Mirror Directus schema\\n3. Frontend Interfaces → Match API responses\\n4. Astro Components → Typed data with autocomplete\\n\\nAdding a field:\\n1. Add `github_url` in Directus UI\\n2. Update `WorkProject` in `api/src/lib/directus.ts`\\n3. Update `WorkProject` in `frontend/src/lib/api.ts`\\n4. TypeScript now knows `project.data.github_url`\\n\\nForget step 2 or 3? Build fails.\\n\\n## Lessons Learned\\n\\n### What Worked\\n\\n**Type safety caught bugs early.** No \\"undefined is not an object\\" in production.\\n\\n**Directus admin UI.** Non-developers can update content without code changes.\\n\\n**Docker Compose.** Works locally = works in production.\\n\\n**Content adapter pattern.** Swap CMS by rewriting one file.\\n\\n### What Was Hard\\n\\n**TypeScript interfaces across layers.** Initially defined separately in each layer. Solution: Generate types from Directus schema once.\\n\\n**Docker networking.** Services couldn't reach each other. Solution: Same Docker network. Healthchecks prevent race conditions.\\n\\n**Directus schema design.** Three iterations. Too normalized (too many joins), too flat (duplicated data), finally balanced.\\n\\n### What I'd Do Differently\\n\\n**Start with schema design, not UI.** Built components first, then tried to fit Directus around them. Should be reversed.\\n\\n**Use Directus SDK from start.** Initially wrote raw HTTP. SDK handles auth, filtering, pagination automatically.\\n\\n**Set up Cloudflare Tunnel earlier.** Wasted time on nginx config.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Traefik, Cloudflare Tunnels\\n\\n**Performance:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse: 95+\\n\\n**Workflow:**\\n1. Edit in Directus\\n2. Changes appear instantly (SSR)\\n3. No build, no deployment\\n\\n## Key Files\\n\\n- `api/src/index.ts` - Hono routes\\n- `api/src/lib/directus.ts` - Type-safe queries\\n- `frontend/src/lib/api.ts` - Fetch wrappers\\n- `frontend/src/content/index.ts` - Content adapter\\n- `frontend/src/pages/work/[slug].astro` - Dynamic routes\\n- `compose.yaml` - Docker orchestration\\n\\n---\\n\\n**Template:** Felix Macaspac's v0.dev minimalist portfolio (v0.app/templates/minimalist-portfolio-1DPeR9dunMc)\\n"}	{"title":"v0 to Production","content":"Most tutorials stop at \\"here's the template.\\" This shows what comes after: integrating a CMS, building a type-safe API, and deploying with Docker.\\n\\n## The Challenge: Static → Dynamic\\n\\nv0.dev delivers hardcoded UI components:\\n\\n```tsx\\n// Before\\nconst projects = [\\n  { title: \\"Project 1\\", description: \\"...\\" }\\n]\\n```\\n\\nThe goal: Replace with a CMS so content updates don't require code changes:\\n\\n```tsx\\n// After\\nconst projects = await api.getWorkProjects()\\n```\\n\\n## Architecture Decisions\\n\\n### Astro over Next.js\\n\\nContent-first sites don't need React's runtime. Astro ships zero JavaScript by default and builds faster.\\n\\n### Hono over Express\\n\\nHono: 12KB. Express: 200KB+. Better TypeScript DX with type-safe routing:\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')\\n  const project = await getWorkProject(slug)\\n  if (!project) return c.json({ error: 'Not found' }, 404)\\n  return c.json({ data: project })\\n})\\n```\\n\\n### Directus over Strapi/Payload\\n\\nBest admin UI. PostgreSQL-backed. TypeScript SDK with auto-generated types.\\n\\n### Docker Compose\\n\\nIdentical dev/prod environments:\\n\\n```yaml\\nservices:\\n  api:\\n    build: ./api\\n    expose: [\\"3000\\"]\\n    healthcheck:\\n      test: [\\"CMD\\", \\"node\\", \\"-e\\", \\"require('http').get(...)\\"]\\n      interval: 30s\\n\\n  frontend:\\n    build: ./frontend\\n    environment:\\n      API_URL: http://astro-hono-api:3000\\n    depends_on:\\n      api:\\n        condition: service_healthy\\n```\\n\\n### Cloudflare Tunnels\\n\\nNo port forwarding. No firewall config. Free HTTPS. DDoS protection included:\\n\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\n## Implementation\\n\\n### 1. Directus Schema\\n\\n```typescript\\n// api/src/lib/directus.ts\\ninterface WorkProject {\\n  id: number\\n  slug: string              // SEO-friendly URLs\\n  title: string\\n  company: string\\n  role: string\\n  year: string\\n  description: string\\n  content?: string          // Markdown for case studies\\n  technologies: string[]\\n  featured: boolean         // Show on homepage\\n  order?: number            // Manual curation\\n  category?: string         // employment | hackathon | research\\n}\\n```\\n\\n### 2. Type-Safe API Layer\\n\\n```typescript\\n// api/src/lib/directus.ts\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\ninterface Schema {\\n  posts: Post[]\\n  work_projects: WorkProject[]\\n  skills: Skill[]\\n}\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\nexport const getWorkProjects = async () => {\\n  return await directus.request(\\n    readItems('work_projects', {\\n      filter: { status: { _eq: 'published' } },\\n      sort: ['order'],\\n      limit: -1\\n    })\\n  )\\n}\\n```\\n\\nTypeScript knows the data shape at every step. Schema changes surface as compile errors immediately.\\n\\n### 3. Frontend API Client\\n\\n```typescript\\n// frontend/src/lib/api.ts\\nconst API_BASE_URL = import.meta.env.API_URL || 'http://astro-hono-api:3000'\\n\\nexport const api = {\\n  async getWorkProject(slug: string): Promise<WorkProjectResponse> {\\n    const response = await fetch(\\n      `${API_BASE_URL}/api/work-projects/${encodeURIComponent(slug)}`\\n    )\\n    if (!response.ok) throw new Error('Failed to fetch')\\n    return response.json()\\n  }\\n}\\n```\\n\\nEnvironment variables switch between Docker internal network (dev) and Cloudflare Tunnel (prod).\\n\\n### 4. Content Adapter Pattern\\n\\nAstro expects content collections. Directus provides an API. The adapter bridges them:\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  const project = response.data\\n  return {\\n    slug: project.slug,\\n    data: {\\n      title: project.title,\\n      company: project.company,\\n      technologies: project.technologies || [],\\n      content: project.content\\n    }\\n  }\\n}\\n```\\n\\nThis means:\\n- Astro pages unchanged\\n- CMS swappable (rewrite adapter only)\\n- Type safety preserved\\n\\n### 5. Dynamic Routes\\n\\n```astro\\n---\\n// pages/work/[slug].astro\\nimport { getWorkProject } from '../../content'\\n\\nconst { slug } = Astro.params\\nconst project = await getWorkProject(slug)\\nif (!project) return Astro.redirect('/404')\\n---\\n\\n<Layout title={project.data.title}>\\n  <h1>{project.data.title}</h1>\\n  <p>{project.data.role} @ {project.data.company}</p>\\n\\n  {project.data.technologies.map(tech => (\\n    <Tag text={tech} />\\n  ))}\\n</Layout>\\n```\\n\\nFlow: **URL → Astro → Adapter → API → Directus → PostgreSQL**\\n\\nEach layer adds type safety. Misspelled fields fail at build time.\\n\\n## The Type Safety Chain\\n\\nTypes flow through every layer:\\n\\n1. Directus Schema → Database collections\\n2. API Interfaces → Mirror Directus schema\\n3. Frontend Interfaces → Match API responses\\n4. Astro Components → Typed data with autocomplete\\n\\nAdding a field:\\n1. Add `github_url` in Directus UI\\n2. Update `WorkProject` in `api/src/lib/directus.ts`\\n3. Update `WorkProject` in `frontend/src/lib/api.ts`\\n4. TypeScript now knows `project.data.github_url`\\n\\nForget step 2 or 3? Build fails.\\n\\n## Lessons Learned\\n\\n### What Worked\\n\\n**Type safety caught bugs early.** No \\"undefined is not an object\\" in production.\\n\\n**Directus admin UI.** Non-developers can update content without code changes.\\n\\n**Docker Compose.** Works locally = works in production.\\n\\n**Content adapter pattern.** Swap CMS by rewriting one file.\\n\\n### What Was Hard\\n\\n**TypeScript interfaces across layers.** Initially defined separately in each layer. Solution: Generate types from Directus schema once.\\n\\n**Docker networking.** Services couldn't reach each other. Solution: Same Docker network. Healthchecks prevent race conditions.\\n\\n**Directus schema design.** Three iterations. Too normalized (too many joins), too flat (duplicated data), finally balanced.\\n\\n### What I'd Do Differently\\n\\n**Start with schema design, not UI.** Built components first, then tried to fit Directus around them. Should be reversed.\\n\\n**Use Directus SDK from start.** Initially wrote raw HTTP. SDK handles auth, filtering, pagination automatically.\\n\\n**Set up Cloudflare Tunnel earlier.** Wasted time on nginx config.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Traefik, Cloudflare Tunnels\\n\\n**Performance:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse: 95+\\n\\n**Workflow:**\\n1. Edit in Directus\\n2. Changes appear instantly (SSR)\\n3. No build, no deployment\\n\\n## Key Files\\n\\n- `api/src/index.ts` - Hono routes\\n- `api/src/lib/directus.ts` - Type-safe queries\\n- `frontend/src/lib/api.ts` - Fetch wrappers\\n- `frontend/src/content/index.ts` - Content adapter\\n- `frontend/src/pages/work/[slug].astro` - Dynamic routes\\n- `compose.yaml` - Docker orchestration\\n\\n---\\n\\n**Template:** Felix Macaspac's v0.dev minimalist portfolio (v0.app/templates/minimalist-portfolio-1DPeR9dunMc)\\n","date_updated":"2025-10-14T06:30:22.528Z"}	\N	\N
154	181	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:50:03.295Z","title":"v0 to Production","published":true,"content":"# Building Production Sites with AI: Why Curation Beats Automation\\n\\nOne day of prompting for a production-ready portfolio. I knew what to ask for, and it's magical.\\n\\n## The Setup\\n\\n**What I saw:** v0.dev templates at an AWS event locked to Vercel's framework.\\n\\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\\n\\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\\n\\n**Why it worked:** Curation and taste. Not because AI figured it out.\\n\\n## What AI Gives You Without Direction\\n\\nLeft to its own devices, Claude Code suggests:\\n\\n**The default stack:**\\n- Express (because it's popular)\\n- Basic JavaScript (because it's simple)\\n- Hardcoded data (because it works)\\n- Generic placeholders everywhere\\n\\n**What you get:** Something that runs. Nothing you'd ship.\\n\\nThis is the trap: AI coding tools *work*, but they optimize for \\"runs quickly\\" not \\"production-grade.\\"\\n\\n## What Changes with Curation\\n\\nWhen you know what exists, you can prompt differently.\\n\\n**Without curation:**\\n> \\"Build me a portfolio site\\"\\n\\nResult: Next.js with hardcoded content. Generic. Forgettable.\\n\\n**With curation:**\\n> \\"I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe.\\"\\n\\nResult: Production architecture in a day.\\n\\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\\n\\n## Where I Actually Learned\\n\\n### Tech Events\\n\\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: \\"Great UI, wrong stack for my needs.\\"\\n\\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\\n\\n### The Internet Annals\\n\\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\\n\\nNot tutorials. Real people discussing real trade-offs.\\n\\n### Small Experiments with Claude Code\\n\\nBuilding throwaway projects:\\n- \\"Show me how Directus works\\"\\n- \\"What's the Hono API surface look like?\\"\\n- \\"How does Astro handle dynamic routes?\\"\\n\\nRudimentary understanding. Just enough to know what's possible.\\n\\n## The Moment of Synthesis\\n\\nv0.dev templates are beautiful. But I wanted:\\n- Astro (better for content than Next.js)\\n- Self-hosted (not Vercel-locked)\\n- Directus (better admin UI than competitors)\\n- Hono (lighter than Express)\\n\\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\\n\\n## What One Day of Prompting Looks Like\\n\\n### Morning: The Conversion\\n\\n**Me:** \\"This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework.\\"\\n\\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\\n\\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\\n\\n### Afternoon: The Integration\\n\\n**Me:** \\"Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API.\\"\\n\\n**Claude Code:** Implements the adapter. Type-safe throughout.\\n\\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\\n\\n### Evening: The Deployment\\n\\n**Me:** \\"Docker Compose. Frontend, API, Directus. Healthchecks so they start in order.\\"\\n\\n**Claude Code:** Generates docker-compose.yml. We debug networking.\\n\\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\\n\\n## The LLM-Driven Issue Loop\\n\\nThis is where Sonnet 4.5 shines:\\n\\n**Pattern:**\\n1. Build a feature\\n2. Test it\\n3. Hit an error\\n4. Paste error to Claude Code\\n5. It suggests fix\\n6. Repeat\\n\\n**Example:**\\n- Docker services can't reach each other\\n- Paste error logs\\n- \\"Add them all to the same network\\"\\n- Works\\n\\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\\n\\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\\n\\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\\n\\n## What Curation Actually Means\\n\\n### 1. Knowing What Exists\\n\\nI can't ask for Hono if I don't know it exists. I learned it from:\\n- Tech event hallway conversation\\n- Seeing it on a \\"lightweight Node frameworks\\" list\\n- Building a throwaway API to understand it\\n\\n**The work:** Self-directed learning. Tech events. Experimentation.\\n\\n### 2. Understanding Trade-offs\\n\\nWhen Claude Code suggests Express, I know to push back: \\"What about Hono?\\"\\n\\nWhen it suggests Strapi, I counter with: \\"Directus has a better admin UI.\\"\\n\\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\\n\\n### 3. Recognizing Good Architecture\\n\\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\\n- Separates concerns\\n- Keeps Astro pages clean\\n- Makes CMS swappable\\n\\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\\n\\n### 4. Directing, Not Just Accepting\\n\\nDefault: \\"Build me X\\" → AI chooses everything\\n\\nCurated: \\"I want A, B, C integrated. Show me how\\" → You choose, AI implements\\n\\n**The difference:** Agency. You're in control.\\n\\n## Why This Moment Matters\\n\\n### The Timing\\n\\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\\n\\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\\n\\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\\n\\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\\n\\n### What Makes This Reproducible\\n\\nNot \\"use these exact tools.\\"\\n\\nBut: **Build your curation muscle, then execute with AI.**\\n\\n**How to build curation:**\\n1. Go to tech events (see tools demoed, hear hallway chatter)\\n2. Dig through forums (understand why people choose X over Y)\\n3. Build small experiments (gain rudimentary understanding)\\n4. Develop taste (know when \\"good enough\\" vs \\"production-grade\\")\\n\\n**Then when Sonnet 4.5 (or better) exists:**\\n- You can name what you want\\n- AI handles implementation details\\n- One day of focused work = production site\\n\\n## The Honest Comparison\\n\\n### Without Curation\\n**Prompt:** \\"Build me a portfolio site\\"\\n\\n**Result:** Express + basic JS + placeholders\\n\\n**Time to production:** Weeks of refactoring to make it real\\n\\n### With Curation\\n**Prompt:** \\"Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment.\\"\\n\\n**Result:** Production-grade architecture from day one\\n\\n**Time to production:** One day of focused prompting\\n\\n**The difference:** I did the learning beforehand. AI does the implementation now.\\n\\n## What You Actually Need to Learn\\n\\n**Not from AI:**\\n- What tools exist in the ecosystem\\n- Why people choose specific tools\\n- Trade-offs between options\\n- What \\"production-grade\\" looks like\\n\\n**From AI:**\\n- How to integrate specific tools\\n- Configuration syntax\\n- Implementation patterns\\n- Fixing specific errors\\n\\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\\n\\n## The Pattern\\n\\n**Phase 1: Self-Directed Learning**\\n- Attend tech events\\n- Read forums and GitHub issues\\n- Experiment with tools in isolation\\n- Develop opinions about trade-offs\\n\\n**Phase 2: Small Experiments**\\n- Build throwaway projects with Claude Code\\n- Gain rudimentary understanding\\n- Learn what's possible, what's hard\\n\\n**Phase 3: Recognition**\\n- \\"I know what I want to build\\"\\n- \\"I know which tools fit together\\"\\n- \\"I can direct an AI toward this vision\\"\\n\\n**Phase 4: Execution**\\n- One day of focused prompting\\n- LLM-driven issue loop (error → fix → repeat)\\n- Production-grade result\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Timeline:**\\n- Months of learning (events, experiments, forums)\\n- One day of building (prompting + iteration)\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\\n\\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\\n\\n## The Real Unlock\\n\\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\\n\\n**2025:** You need to know what to build and why. AI builds it for you.\\n\\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\\n\\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\\n\\n**When AI amplifies it:** When you can say \\"I want A, B, C integrated\\" and the AI handles implementation.\\n\\nThe tools haven't changed. The leverage has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\\n"}	{"content":"# Building Production Sites with AI: Why Curation Beats Automation\\n\\nOne day of prompting for a production-ready portfolio. I knew what to ask for, and it's magical.\\n\\n## The Setup\\n\\n**What I saw:** v0.dev templates at an AWS event locked to Vercel's framework.\\n\\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\\n\\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\\n\\n**Why it worked:** Curation and taste. Not because AI figured it out.\\n\\n## What AI Gives You Without Direction\\n\\nLeft to its own devices, Claude Code suggests:\\n\\n**The default stack:**\\n- Express (because it's popular)\\n- Basic JavaScript (because it's simple)\\n- Hardcoded data (because it works)\\n- Generic placeholders everywhere\\n\\n**What you get:** Something that runs. Nothing you'd ship.\\n\\nThis is the trap: AI coding tools *work*, but they optimize for \\"runs quickly\\" not \\"production-grade.\\"\\n\\n## What Changes with Curation\\n\\nWhen you know what exists, you can prompt differently.\\n\\n**Without curation:**\\n> \\"Build me a portfolio site\\"\\n\\nResult: Next.js with hardcoded content. Generic. Forgettable.\\n\\n**With curation:**\\n> \\"I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe.\\"\\n\\nResult: Production architecture in a day.\\n\\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\\n\\n## Where I Actually Learned\\n\\n### Tech Events\\n\\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: \\"Great UI, wrong stack for my needs.\\"\\n\\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\\n\\n### The Internet Annals\\n\\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\\n\\nNot tutorials. Real people discussing real trade-offs.\\n\\n### Small Experiments with Claude Code\\n\\nBuilding throwaway projects:\\n- \\"Show me how Directus works\\"\\n- \\"What's the Hono API surface look like?\\"\\n- \\"How does Astro handle dynamic routes?\\"\\n\\nRudimentary understanding. Just enough to know what's possible.\\n\\n## The Moment of Synthesis\\n\\nv0.dev templates are beautiful. But I wanted:\\n- Astro (better for content than Next.js)\\n- Self-hosted (not Vercel-locked)\\n- Directus (better admin UI than competitors)\\n- Hono (lighter than Express)\\n\\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\\n\\n## What One Day of Prompting Looks Like\\n\\n### Morning: The Conversion\\n\\n**Me:** \\"This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework.\\"\\n\\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\\n\\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\\n\\n### Afternoon: The Integration\\n\\n**Me:** \\"Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API.\\"\\n\\n**Claude Code:** Implements the adapter. Type-safe throughout.\\n\\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\\n\\n### Evening: The Deployment\\n\\n**Me:** \\"Docker Compose. Frontend, API, Directus. Healthchecks so they start in order.\\"\\n\\n**Claude Code:** Generates docker-compose.yml. We debug networking.\\n\\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\\n\\n## The LLM-Driven Issue Loop\\n\\nThis is where Sonnet 4.5 shines:\\n\\n**Pattern:**\\n1. Build a feature\\n2. Test it\\n3. Hit an error\\n4. Paste error to Claude Code\\n5. It suggests fix\\n6. Repeat\\n\\n**Example:**\\n- Docker services can't reach each other\\n- Paste error logs\\n- \\"Add them all to the same network\\"\\n- Works\\n\\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\\n\\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\\n\\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\\n\\n## What Curation Actually Means\\n\\n### 1. Knowing What Exists\\n\\nI can't ask for Hono if I don't know it exists. I learned it from:\\n- Tech event hallway conversation\\n- Seeing it on a \\"lightweight Node frameworks\\" list\\n- Building a throwaway API to understand it\\n\\n**The work:** Self-directed learning. Tech events. Experimentation.\\n\\n### 2. Understanding Trade-offs\\n\\nWhen Claude Code suggests Express, I know to push back: \\"What about Hono?\\"\\n\\nWhen it suggests Strapi, I counter with: \\"Directus has a better admin UI.\\"\\n\\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\\n\\n### 3. Recognizing Good Architecture\\n\\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\\n- Separates concerns\\n- Keeps Astro pages clean\\n- Makes CMS swappable\\n\\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\\n\\n### 4. Directing, Not Just Accepting\\n\\nDefault: \\"Build me X\\" → AI chooses everything\\n\\nCurated: \\"I want A, B, C integrated. Show me how\\" → You choose, AI implements\\n\\n**The difference:** Agency. You're in control.\\n\\n## Why This Moment Matters\\n\\n### The Timing\\n\\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\\n\\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\\n\\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\\n\\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\\n\\n### What Makes This Reproducible\\n\\nNot \\"use these exact tools.\\"\\n\\nBut: **Build your curation muscle, then execute with AI.**\\n\\n**How to build curation:**\\n1. Go to tech events (see tools demoed, hear hallway chatter)\\n2. Dig through forums (understand why people choose X over Y)\\n3. Build small experiments (gain rudimentary understanding)\\n4. Develop taste (know when \\"good enough\\" vs \\"production-grade\\")\\n\\n**Then when Sonnet 4.5 (or better) exists:**\\n- You can name what you want\\n- AI handles implementation details\\n- One day of focused work = production site\\n\\n## The Honest Comparison\\n\\n### Without Curation\\n**Prompt:** \\"Build me a portfolio site\\"\\n\\n**Result:** Express + basic JS + placeholders\\n\\n**Time to production:** Weeks of refactoring to make it real\\n\\n### With Curation\\n**Prompt:** \\"Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment.\\"\\n\\n**Result:** Production-grade architecture from day one\\n\\n**Time to production:** One day of focused prompting\\n\\n**The difference:** I did the learning beforehand. AI does the implementation now.\\n\\n## What You Actually Need to Learn\\n\\n**Not from AI:**\\n- What tools exist in the ecosystem\\n- Why people choose specific tools\\n- Trade-offs between options\\n- What \\"production-grade\\" looks like\\n\\n**From AI:**\\n- How to integrate specific tools\\n- Configuration syntax\\n- Implementation patterns\\n- Fixing specific errors\\n\\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\\n\\n## The Pattern\\n\\n**Phase 1: Self-Directed Learning**\\n- Attend tech events\\n- Read forums and GitHub issues\\n- Experiment with tools in isolation\\n- Develop opinions about trade-offs\\n\\n**Phase 2: Small Experiments**\\n- Build throwaway projects with Claude Code\\n- Gain rudimentary understanding\\n- Learn what's possible, what's hard\\n\\n**Phase 3: Recognition**\\n- \\"I know what I want to build\\"\\n- \\"I know which tools fit together\\"\\n- \\"I can direct an AI toward this vision\\"\\n\\n**Phase 4: Execution**\\n- One day of focused prompting\\n- LLM-driven issue loop (error → fix → repeat)\\n- Production-grade result\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Timeline:**\\n- Months of learning (events, experiments, forums)\\n- One day of building (prompting + iteration)\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\\n\\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\\n\\n## The Real Unlock\\n\\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\\n\\n**2025:** You need to know what to build and why. AI builds it for you.\\n\\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\\n\\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\\n\\n**When AI amplifies it:** When you can say \\"I want A, B, C integrated\\" and the AI handles implementation.\\n\\nThe tools haven't changed. The leverage has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\\n","date_updated":"2025-10-14T06:50:03.295Z"}	\N	\N
81	88	work_projects	8	{"title":"Univar Solutions - Data Engineering","slug":"potion-data-engineering","company":"Potion (via Univar Solutions)","role":"Data Analyst","year":"2022","duration":"Contract","description":"Built data reconciliation pipeline for chemical formula database. Introduced Jupyter notebooks to annotation team, enabling large-scale cleanup effort.","content":"## Challenge\\n\\nChemical formulation database needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Built reconciliation system matching outdated names to original IDs\\n- Enabled bidirectional sync between golden dataset and production DB\\n- Automated cleanup and consolidation of redundant labels\\n\\n### Team Enablement\\n- Introduced Jupyter notebooks to annotation team\\n- Created tools for efficient data cleanup\\n- Trained team on data engineering best practices\\n\\n## Impact\\n- Saved hundreds of hours of manual work\\n- Made previously impossible database updates feasible\\n- Improved data quality for Univar Solutions chemical supply network\\n\\n## Technologies\\n- Data engineering and ETL\\n- Database reconciliation algorithms\\n- Jupyter for collaborative data work","technologies":["Python","Jupyter","Data Engineering","ETL","Database Systems"],"featured":false,"order":8,"status":"published"}	{"title":"Univar Solutions - Data Engineering","slug":"potion-data-engineering","company":"Potion (via Univar Solutions)","role":"Data Analyst","year":"2022","duration":"Contract","description":"Built data reconciliation pipeline for chemical formula database. Introduced Jupyter notebooks to annotation team, enabling large-scale cleanup effort.","content":"## Challenge\\n\\nChemical formulation database needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Built reconciliation system matching outdated names to original IDs\\n- Enabled bidirectional sync between golden dataset and production DB\\n- Automated cleanup and consolidation of redundant labels\\n\\n### Team Enablement\\n- Introduced Jupyter notebooks to annotation team\\n- Created tools for efficient data cleanup\\n- Trained team on data engineering best practices\\n\\n## Impact\\n- Saved hundreds of hours of manual work\\n- Made previously impossible database updates feasible\\n- Improved data quality for Univar Solutions chemical supply network\\n\\n## Technologies\\n- Data engineering and ETL\\n- Database reconciliation algorithms\\n- Jupyter for collaborative data work","technologies":["Python","Jupyter","Data Engineering","ETL","Database Systems"],"featured":false,"order":8,"status":"published"}	\N	\N
82	89	skills	1	{"name":"Claude","category":"aiml","proficiency":"expert","order":1,"featured":true}	{"name":"Claude","category":"aiml","proficiency":"expert","order":1,"featured":true}	\N	\N
83	90	skills	2	{"name":"ChatGPT","category":"aiml","proficiency":"expert","order":2,"featured":true}	{"name":"ChatGPT","category":"aiml","proficiency":"expert","order":2,"featured":true}	\N	\N
84	91	skills	3	{"name":"LangChain","category":"aiml","proficiency":"expert","order":3,"featured":true}	{"name":"LangChain","category":"aiml","proficiency":"expert","order":3,"featured":true}	\N	\N
85	92	skills	4	{"name":"BAML","category":"aiml","proficiency":"intermediate","order":4,"featured":true}	{"name":"BAML","category":"aiml","proficiency":"intermediate","order":4,"featured":true}	\N	\N
86	93	skills	5	{"name":"Weaviate","category":"aiml","proficiency":"intermediate","order":5,"featured":true}	{"name":"Weaviate","category":"aiml","proficiency":"intermediate","order":5,"featured":true}	\N	\N
87	94	skills	6	{"name":"LlamaIndex","category":"aiml","proficiency":"intermediate","order":6,"featured":true}	{"name":"LlamaIndex","category":"aiml","proficiency":"intermediate","order":6,"featured":true}	\N	\N
88	95	skills	7	{"name":"CrewAI","category":"aiml","proficiency":"intermediate","order":7,"featured":false}	{"name":"CrewAI","category":"aiml","proficiency":"intermediate","order":7,"featured":false}	\N	\N
89	96	skills	8	{"name":"PyTorch","category":"aiml","proficiency":"intermediate","order":8,"featured":false}	{"name":"PyTorch","category":"aiml","proficiency":"intermediate","order":8,"featured":false}	\N	\N
90	97	skills	9	{"name":"HuggingFace","category":"aiml","proficiency":"intermediate","order":9,"featured":false}	{"name":"HuggingFace","category":"aiml","proficiency":"intermediate","order":9,"featured":false}	\N	\N
91	98	skills	10	{"name":"Stable Diffusion","category":"aiml","proficiency":"intermediate","order":10,"featured":false}	{"name":"Stable Diffusion","category":"aiml","proficiency":"intermediate","order":10,"featured":false}	\N	\N
92	99	skills	11	{"name":"Python","category":"backend","proficiency":"expert","order":11,"featured":true}	{"name":"Python","category":"backend","proficiency":"expert","order":11,"featured":true}	\N	\N
93	100	skills	12	{"name":"FastAPI","category":"backend","proficiency":"expert","order":12,"featured":true}	{"name":"FastAPI","category":"backend","proficiency":"expert","order":12,"featured":true}	\N	\N
94	101	skills	13	{"name":"Node.js","category":"backend","proficiency":"expert","order":13,"featured":true}	{"name":"Node.js","category":"backend","proficiency":"expert","order":13,"featured":true}	\N	\N
95	102	skills	14	{"name":"Rust","category":"backend","proficiency":"intermediate","order":14,"featured":true}	{"name":"Rust","category":"backend","proficiency":"intermediate","order":14,"featured":true}	\N	\N
96	103	skills	15	{"name":"TypeScript","category":"frontend","proficiency":"expert","order":15,"featured":true}	{"name":"TypeScript","category":"frontend","proficiency":"expert","order":15,"featured":true}	\N	\N
97	104	skills	16	{"name":"React","category":"frontend","proficiency":"expert","order":16,"featured":true}	{"name":"React","category":"frontend","proficiency":"expert","order":16,"featured":true}	\N	\N
98	105	skills	17	{"name":"Astro","category":"frontend","proficiency":"expert","order":17,"featured":true}	{"name":"Astro","category":"frontend","proficiency":"expert","order":17,"featured":true}	\N	\N
99	106	skills	18	{"name":"Tailwind CSS","category":"frontend","proficiency":"expert","order":18,"featured":true}	{"name":"Tailwind CSS","category":"frontend","proficiency":"expert","order":18,"featured":true}	\N	\N
100	107	skills	19	{"name":"Docker","category":"devops","proficiency":"expert","order":19,"featured":true}	{"name":"Docker","category":"devops","proficiency":"expert","order":19,"featured":true}	\N	\N
101	108	skills	20	{"name":"flox","category":"devops","proficiency":"intermediate","order":20,"featured":false}	{"name":"flox","category":"devops","proficiency":"intermediate","order":20,"featured":false}	\N	\N
102	109	skills	21	{"name":"n8n","category":"devops","proficiency":"intermediate","order":21,"featured":false}	{"name":"n8n","category":"devops","proficiency":"intermediate","order":21,"featured":false}	\N	\N
103	110	social_links	1	{"name":"GitHub","handle":"@johnhkchen","url":"https://github.com/johnhkchen","icon":"github","order":1,"visible":true}	{"name":"GitHub","handle":"@johnhkchen","url":"https://github.com/johnhkchen","icon":"github","order":1,"visible":true}	\N	\N
104	111	social_links	2	{"name":"LinkedIn","handle":"john-chen-364294101","url":"https://www.linkedin.com/in/john-chen-364294101/","icon":"linkedin","order":2,"visible":true}	{"name":"LinkedIn","handle":"john-chen-364294101","url":"https://www.linkedin.com/in/john-chen-364294101/","icon":"linkedin","order":2,"visible":true}	\N	\N
105	112	social_links	3	{"name":"Email","handle":"john.hk.chen@gmail.com","url":"mailto:john.hk.chen@gmail.com","icon":"email","order":3,"visible":true}	{"name":"Email","handle":"john.hk.chen@gmail.com","url":"mailto:john.hk.chen@gmail.com","icon":"email","order":3,"visible":true}	\N	\N
140	161	skills	6	{"id":6,"name":"LlamaIndex","category":"aiml","proficiency":"intermediate","order":6,"featured":false}	{"featured":false}	\N	\N
148	174	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:36:53.308Z","title":"Building Production Sites with AI: A Reproducible Approach","published":true,"content":"# Building Production Sites with AI: A Reproducible Approach\\n\\nv0.dev gives you a template. Claude Code makes it production-ready. This is the methodology.\\n\\n## The Problem Space\\n\\nYou have a beautiful UI template. You need it to work with real data, deploy to production, and allow non-developers to update content. Traditional tutorials show you *what* to build. This shows you *how to prompt* an AI to build it.\\n\\n## The Prompt Framework\\n\\n### 1. Start with Constraints, Not Solutions\\n\\n**Don't prompt:** \\"Build me an API with Express\\"\\n\\n**Do prompt:** \\"I need to connect this Astro frontend to Directus. What's the lightest-weight option that maintains type safety?\\"\\n\\nClaude Code suggested Hono (12KB vs Express's 200KB+). I wouldn't have known it existed.\\n\\nThe pattern: **State the problem and constraints. Let the AI propose solutions.**\\n\\n### 2. Ask for Architectural Decisions\\n\\n**The prompt:**\\n> \\"I'm building a portfolio site. I need it to be fast, SEO-friendly, support markdown content, and allow my partner to update projects without touching code. What stack would you recommend?\\"\\n\\n**Claude Code's response:**\\n- Astro (content-first, minimal JavaScript)\\n- Hono API layer (type-safe, lightweight)\\n- Directus CMS (best admin UI, PostgreSQL-backed)\\n- Docker Compose (reproducible environments)\\n\\nI asked *why* for each choice. The explanations taught me trade-offs I'd have spent hours researching.\\n\\n**The insight:** AI has context on the entire ecosystem. Use it as an architecture advisor.\\n\\n### 3. Iterate on \\"Show Me How\\"\\n\\nInstead of asking for complete implementations, request incremental examples:\\n\\n**Progression:**\\n1. \\"Show me how to set up the Directus TypeScript client\\"\\n2. \\"Now show me how to fetch a single work project by slug\\"\\n3. \\"How do I make this work with Astro's content collection pattern?\\"\\n\\nEach step builds on the last. Each answer includes code I can verify works before moving forward.\\n\\n**Why this matters:** You stay in control. You understand each piece before adding complexity.\\n\\n### 4. Prompt for Type Safety Chains\\n\\n**The prompt that changed everything:**\\n> \\"I want TypeScript to catch errors if I misspell a field name anywhere from Directus to the frontend. How do I structure this?\\"\\n\\nClaude Code designed the entire type safety chain:\\n- Directus schema interfaces\\n- API layer types that mirror them\\n- Frontend types that match API responses\\n- Astro components with full autocomplete\\n\\nOne prompt. Twenty minutes of work. Production-grade type safety.\\n\\n### 5. Ask \\"What Would Go Wrong?\\"\\n\\nAfter implementing a feature:\\n\\n**The prompt:**\\n> \\"I have Docker services for Directus, API, and frontend. What could go wrong in production?\\"\\n\\n**Claude Code's response:**\\n- Services might start in wrong order → Add healthchecks\\n- Network isolation issues → Use same Docker network\\n- Race conditions on startup → Add `depends_on` with conditions\\n\\nThis is defensive architecture from a single question.\\n\\n## The Workflow in Practice\\n\\n### Real Session Example: Adding the Content Adapter\\n\\n**Me:** \\"Astro expects content collections. Directus is an API. How do I bridge them?\\"\\n\\n**Claude Code:** \\"Use an adapter pattern. Here's the structure...\\"\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  return {\\n    slug: project.slug,\\n    data: { /* transformed to Astro format */ }\\n  }\\n}\\n```\\n\\n**Me:** \\"Why this approach vs directly calling Directus from Astro?\\"\\n\\n**Claude Code:** \\"Security boundary, type safety, easy to swap CMS later. If you outgrow Directus, rewrite this one file.\\"\\n\\n**The pattern:** Request implementation → Understand trade-offs → Iterate if needed.\\n\\n## What Makes This Reproducible\\n\\n### 1. You Don't Need to Know the Ecosystem\\n\\nI'd never used Hono. Barely knew Directus. Claude Code:\\n- Suggested them based on requirements\\n- Showed exactly how to use them\\n- Explained when I'd outgrow them\\n\\n**The unlock:** Prompt with your constraints, not your assumptions.\\n\\n### 2. It's Not Magic; It's Methodology\\n\\nThe workflow:\\n1. Define what you need (content updates without deployments)\\n2. State your constraints (self-hosted, type-safe, fast)\\n3. Ask for recommendations\\n4. Request implementations with explanations\\n5. Iterate when you hit edge cases\\n\\nAnyone can follow this. The code changes. The approach doesn't.\\n\\n### 3. You Stay in the Driver's Seat\\n\\nI made every architectural decision. Claude Code provided:\\n- Options with trade-offs\\n- Implementation details\\n- \\"Here's what could break\\" analysis\\n\\nI still chose Cloudflare Tunnels over nginx. Still decided on Docker Compose over Kubernetes. Still picked PostgreSQL over MongoDB.\\n\\n**The difference:** Those decisions took minutes instead of days of research.\\n\\n## The Meta-Lesson\\n\\n### Traditional Approach\\n1. Research stack options (days)\\n2. Read documentation (days)\\n3. Set up boilerplate (hours)\\n4. Debug integration issues (days)\\n5. Discover you chose wrong tools (restart)\\n\\n**Estimated time:** 2-4 weeks for production-ready\\n\\n### AI-Assisted Approach\\n1. Describe requirements and constraints\\n2. Evaluate AI-proposed architecture\\n3. Implement incrementally with AI guidance\\n4. Ask \\"what breaks?\\" at each step\\n5. Deploy with AI-generated configs\\n\\n**Actual time:** 10 hours active work\\n\\n### What Changed\\n\\nNot the fundamentals. Astro is still Astro. Docker is still Docker. TypeScript is still TypeScript.\\n\\nWhat changed: **No more guessing which tools fit together.** No more reading docs for tools you won't use.\\n\\n## The Limitations\\n\\n### Where AI Excels\\n- Architecture recommendations based on constraints\\n- Boilerplate and integration code\\n- Type system design\\n- Configuration files\\n- \\"What could break?\\" analysis\\n\\n### Where You Still Decide\\n- Content strategy (what's worth showing?)\\n- Design choices (minimalism vs maximalism)\\n- Accuracy of content (AI writes well, verify facts)\\n- When to ship (perfect vs good enough)\\n\\n### What You Still Learn\\n\\nI now understand:\\n- Why type safety matters across boundaries\\n- When Docker healthchecks prevent race conditions\\n- How content adapters enable flexibility\\n\\nI didn't just get a working site. I learned architecture patterns I'll use again.\\n\\n## How to Apply This\\n\\n### Starting a New Project\\n\\n**Step 1:** Write a constraint prompt\\n```\\nI need a [type of site] that:\\n- [Performance requirement]\\n- [Content management need]\\n- [Deployment constraint]\\n- [Team skill level]\\n\\nWhat stack would work?\\n```\\n\\n**Step 2:** For each suggested tool, ask:\\n- \\"Why this over [alternative]?\\"\\n- \\"When would I outgrow this?\\"\\n- \\"Show me the integration points\\"\\n\\n**Step 3:** Implement incrementally\\n- Request one feature at a time\\n- Verify it works before adding complexity\\n- Ask \\"what breaks?\\" after each addition\\n\\n**Step 4:** Iterate on rough edges\\n- \\"This works but feels brittle. How do I make it production-ready?\\"\\n- \\"What am I missing for error handling?\\"\\n\\n### The Results\\n\\n**Live:** https://b28.dev\\n\\n**Built in:** 10 hours active work\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Type-safe:** Yes\\n\\n**Self-hosted:** Yes\\n\\n**CMS-backed:** Yes\\n\\n**Could you reproduce this?** Yes. Use the same prompt framework.\\n\\n## The Real Insight\\n\\n2023: You needed to know the ecosystem to build production sites.\\n\\n2025: You need to know how to *describe what you want* and *evaluate options*.\\n\\nThe tools haven't changed. Your workflow has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Methodology:** Constraint-based prompting + incremental implementation + \\"what breaks?\\" analysis\\n"}	{"title":"Building Production Sites with AI: A Reproducible Approach","content":"# Building Production Sites with AI: A Reproducible Approach\\n\\nv0.dev gives you a template. Claude Code makes it production-ready. This is the methodology.\\n\\n## The Problem Space\\n\\nYou have a beautiful UI template. You need it to work with real data, deploy to production, and allow non-developers to update content. Traditional tutorials show you *what* to build. This shows you *how to prompt* an AI to build it.\\n\\n## The Prompt Framework\\n\\n### 1. Start with Constraints, Not Solutions\\n\\n**Don't prompt:** \\"Build me an API with Express\\"\\n\\n**Do prompt:** \\"I need to connect this Astro frontend to Directus. What's the lightest-weight option that maintains type safety?\\"\\n\\nClaude Code suggested Hono (12KB vs Express's 200KB+). I wouldn't have known it existed.\\n\\nThe pattern: **State the problem and constraints. Let the AI propose solutions.**\\n\\n### 2. Ask for Architectural Decisions\\n\\n**The prompt:**\\n> \\"I'm building a portfolio site. I need it to be fast, SEO-friendly, support markdown content, and allow my partner to update projects without touching code. What stack would you recommend?\\"\\n\\n**Claude Code's response:**\\n- Astro (content-first, minimal JavaScript)\\n- Hono API layer (type-safe, lightweight)\\n- Directus CMS (best admin UI, PostgreSQL-backed)\\n- Docker Compose (reproducible environments)\\n\\nI asked *why* for each choice. The explanations taught me trade-offs I'd have spent hours researching.\\n\\n**The insight:** AI has context on the entire ecosystem. Use it as an architecture advisor.\\n\\n### 3. Iterate on \\"Show Me How\\"\\n\\nInstead of asking for complete implementations, request incremental examples:\\n\\n**Progression:**\\n1. \\"Show me how to set up the Directus TypeScript client\\"\\n2. \\"Now show me how to fetch a single work project by slug\\"\\n3. \\"How do I make this work with Astro's content collection pattern?\\"\\n\\nEach step builds on the last. Each answer includes code I can verify works before moving forward.\\n\\n**Why this matters:** You stay in control. You understand each piece before adding complexity.\\n\\n### 4. Prompt for Type Safety Chains\\n\\n**The prompt that changed everything:**\\n> \\"I want TypeScript to catch errors if I misspell a field name anywhere from Directus to the frontend. How do I structure this?\\"\\n\\nClaude Code designed the entire type safety chain:\\n- Directus schema interfaces\\n- API layer types that mirror them\\n- Frontend types that match API responses\\n- Astro components with full autocomplete\\n\\nOne prompt. Twenty minutes of work. Production-grade type safety.\\n\\n### 5. Ask \\"What Would Go Wrong?\\"\\n\\nAfter implementing a feature:\\n\\n**The prompt:**\\n> \\"I have Docker services for Directus, API, and frontend. What could go wrong in production?\\"\\n\\n**Claude Code's response:**\\n- Services might start in wrong order → Add healthchecks\\n- Network isolation issues → Use same Docker network\\n- Race conditions on startup → Add `depends_on` with conditions\\n\\nThis is defensive architecture from a single question.\\n\\n## The Workflow in Practice\\n\\n### Real Session Example: Adding the Content Adapter\\n\\n**Me:** \\"Astro expects content collections. Directus is an API. How do I bridge them?\\"\\n\\n**Claude Code:** \\"Use an adapter pattern. Here's the structure...\\"\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  return {\\n    slug: project.slug,\\n    data: { /* transformed to Astro format */ }\\n  }\\n}\\n```\\n\\n**Me:** \\"Why this approach vs directly calling Directus from Astro?\\"\\n\\n**Claude Code:** \\"Security boundary, type safety, easy to swap CMS later. If you outgrow Directus, rewrite this one file.\\"\\n\\n**The pattern:** Request implementation → Understand trade-offs → Iterate if needed.\\n\\n## What Makes This Reproducible\\n\\n### 1. You Don't Need to Know the Ecosystem\\n\\nI'd never used Hono. Barely knew Directus. Claude Code:\\n- Suggested them based on requirements\\n- Showed exactly how to use them\\n- Explained when I'd outgrow them\\n\\n**The unlock:** Prompt with your constraints, not your assumptions.\\n\\n### 2. It's Not Magic; It's Methodology\\n\\nThe workflow:\\n1. Define what you need (content updates without deployments)\\n2. State your constraints (self-hosted, type-safe, fast)\\n3. Ask for recommendations\\n4. Request implementations with explanations\\n5. Iterate when you hit edge cases\\n\\nAnyone can follow this. The code changes. The approach doesn't.\\n\\n### 3. You Stay in the Driver's Seat\\n\\nI made every architectural decision. Claude Code provided:\\n- Options with trade-offs\\n- Implementation details\\n- \\"Here's what could break\\" analysis\\n\\nI still chose Cloudflare Tunnels over nginx. Still decided on Docker Compose over Kubernetes. Still picked PostgreSQL over MongoDB.\\n\\n**The difference:** Those decisions took minutes instead of days of research.\\n\\n## The Meta-Lesson\\n\\n### Traditional Approach\\n1. Research stack options (days)\\n2. Read documentation (days)\\n3. Set up boilerplate (hours)\\n4. Debug integration issues (days)\\n5. Discover you chose wrong tools (restart)\\n\\n**Estimated time:** 2-4 weeks for production-ready\\n\\n### AI-Assisted Approach\\n1. Describe requirements and constraints\\n2. Evaluate AI-proposed architecture\\n3. Implement incrementally with AI guidance\\n4. Ask \\"what breaks?\\" at each step\\n5. Deploy with AI-generated configs\\n\\n**Actual time:** 10 hours active work\\n\\n### What Changed\\n\\nNot the fundamentals. Astro is still Astro. Docker is still Docker. TypeScript is still TypeScript.\\n\\nWhat changed: **No more guessing which tools fit together.** No more reading docs for tools you won't use.\\n\\n## The Limitations\\n\\n### Where AI Excels\\n- Architecture recommendations based on constraints\\n- Boilerplate and integration code\\n- Type system design\\n- Configuration files\\n- \\"What could break?\\" analysis\\n\\n### Where You Still Decide\\n- Content strategy (what's worth showing?)\\n- Design choices (minimalism vs maximalism)\\n- Accuracy of content (AI writes well, verify facts)\\n- When to ship (perfect vs good enough)\\n\\n### What You Still Learn\\n\\nI now understand:\\n- Why type safety matters across boundaries\\n- When Docker healthchecks prevent race conditions\\n- How content adapters enable flexibility\\n\\nI didn't just get a working site. I learned architecture patterns I'll use again.\\n\\n## How to Apply This\\n\\n### Starting a New Project\\n\\n**Step 1:** Write a constraint prompt\\n```\\nI need a [type of site] that:\\n- [Performance requirement]\\n- [Content management need]\\n- [Deployment constraint]\\n- [Team skill level]\\n\\nWhat stack would work?\\n```\\n\\n**Step 2:** For each suggested tool, ask:\\n- \\"Why this over [alternative]?\\"\\n- \\"When would I outgrow this?\\"\\n- \\"Show me the integration points\\"\\n\\n**Step 3:** Implement incrementally\\n- Request one feature at a time\\n- Verify it works before adding complexity\\n- Ask \\"what breaks?\\" after each addition\\n\\n**Step 4:** Iterate on rough edges\\n- \\"This works but feels brittle. How do I make it production-ready?\\"\\n- \\"What am I missing for error handling?\\"\\n\\n### The Results\\n\\n**Live:** https://b28.dev\\n\\n**Built in:** 10 hours active work\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Type-safe:** Yes\\n\\n**Self-hosted:** Yes\\n\\n**CMS-backed:** Yes\\n\\n**Could you reproduce this?** Yes. Use the same prompt framework.\\n\\n## The Real Insight\\n\\n2023: You needed to know the ecosystem to build production sites.\\n\\n2025: You need to know how to *describe what you want* and *evaluate options*.\\n\\nThe tools haven't changed. Your workflow has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Methodology:** Constraint-based prompting + incremental implementation + \\"what breaks?\\" analysis\\n","date_updated":"2025-10-14T06:36:53.308Z"}	\N	\N
108	116	directus_permissions	4	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":{"_and":[{"visible":{"_eq":true}}]},"validation":null,"fields":["*"],"presets":null,"collection":"social_links","action":"read"}	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":{"_and":[{"visible":{"_eq":true}}]},"validation":null,"fields":["*"],"presets":null,"collection":"social_links","action":"read"}	\N	\N
109	117	directus_permissions	5	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":{"_and":[{"status":{"_eq":"published"}}]},"validation":null,"fields":["*"],"presets":null,"collection":"work_projects","action":"read"}	{"policy":"abf8a154-5b1c-4a46-ac9c-7300570f4f17","permissions":{"_and":[{"status":{"_eq":"published"}}]},"validation":null,"fields":["*"],"presets":null,"collection":"work_projects","action":"read"}	\N	\N
110	121	work_projects	7	{"id":7,"status":"published","title":"Fitness Planner - Vector Search Application","slug":"fitness-planner","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"AI-powered fitness routine suggester using Weaviate vector database. Transforms user descriptions into personalized workout plans.","content":"## Concept\\n\\nNatural language fitness planning: describe your goals and fitness level, get personalized workout routines.\\n\\n## Technical Implementation\\n\\n### Vector Search\\n- Used Weaviate for semantic workout search\\n- Embedded fitness routines with descriptions\\n- Implemented semantic similarity matching\\n\\n### Example Queries\\n- \\"out of shape 30 year old couch to 5k\\"\\n- \\"strength training for beginners\\"\\n- \\"low impact cardio for seniors\\"\\n\\n### Structured Output\\n- Generated progressive workout plans\\n- Included exercise descriptions and modifications\\n- Suggested timelines and milestones\\n\\n## Learning\\n- Practical vector database implementation\\n- Semantic search for recommendation systems\\n- Rapid prototyping with modern AI tools","technologies":["Weaviate","Vector Search","LLM","Full Stack","RAG"],"featured":true,"order":7,"team":null,"live_url":null,"case_study_url":null}	{"featured":true}	\N	\N
111	122	work_projects	8	{"id":8,"status":"published","title":"Univar Solutions - Data Engineering","slug":"potion-data-engineering","company":"Potion (via Univar Solutions)","role":"Data Analyst","year":"2022","duration":"Contract","description":"Built data reconciliation pipeline for chemical formula database. Introduced Jupyter notebooks to annotation team, enabling large-scale cleanup effort.","content":"## Challenge\\n\\nChemical formulation database needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Built reconciliation system matching outdated names to original IDs\\n- Enabled bidirectional sync between golden dataset and production DB\\n- Automated cleanup and consolidation of redundant labels\\n\\n### Team Enablement\\n- Introduced Jupyter notebooks to annotation team\\n- Created tools for efficient data cleanup\\n- Trained team on data engineering best practices\\n\\n## Impact\\n- Saved hundreds of hours of manual work\\n- Made previously impossible database updates feasible\\n- Improved data quality for Univar Solutions chemical supply network\\n\\n## Technologies\\n- Data engineering and ETL\\n- Database reconciliation algorithms\\n- Jupyter for collaborative data work","technologies":["Python","Jupyter","Data Engineering","ETL","Database Systems"],"featured":true,"order":8,"team":null,"live_url":null,"case_study_url":null}	{"featured":true}	\N	\N
112	124	directus_fields	58	{"sort":17,"interface":"select-dropdown","options":{"choices":[{"text":"Employment","value":"employment"},{"text":"Research","value":"research"},{"text":"Education/Community","value":"education"},{"text":"Hackathon","value":"hackathon"},{"text":"Open Source","value":"open-source"}]},"display":"labels","display_options":{"choices":[{"text":"Employment","value":"employment","foreground":"#FFFFFF","background":"#2563EB"},{"text":"Research","value":"research","foreground":"#FFFFFF","background":"#7C3AED"},{"text":"Education/Community","value":"education","foreground":"#FFFFFF","background":"#059669"},{"text":"Hackathon","value":"hackathon","foreground":"#FFFFFF","background":"#DC2626"},{"text":"Open Source","value":"open-source","foreground":"#FFFFFF","background":"#EA580C"}]},"width":"half","collection":"work_projects","field":"category"}	{"sort":17,"interface":"select-dropdown","options":{"choices":[{"text":"Employment","value":"employment"},{"text":"Research","value":"research"},{"text":"Education/Community","value":"education"},{"text":"Hackathon","value":"hackathon"},{"text":"Open Source","value":"open-source"}]},"display":"labels","display_options":{"choices":[{"text":"Employment","value":"employment","foreground":"#FFFFFF","background":"#2563EB"},{"text":"Research","value":"research","foreground":"#FFFFFF","background":"#7C3AED"},{"text":"Education/Community","value":"education","foreground":"#FFFFFF","background":"#059669"},{"text":"Hackathon","value":"hackathon","foreground":"#FFFFFF","background":"#DC2626"},{"text":"Open Source","value":"open-source","foreground":"#FFFFFF","background":"#EA580C"}]},"width":"half","collection":"work_projects","field":"category"}	\N	\N
113	125	work_projects	1	{"id":1,"status":"published","title":"My Little Soda - Autonomous Coding Agent","slug":"my-little-soda","company":"Open Source","role":"Creator & Maintainer","year":"2024","duration":"Ongoing","description":"GitHub Issues-driven autonomous coding tool that uses LLMs to automatically implement features and fix bugs.","content":"## Overview\\n\\nBuilt an autonomous coding agent that monitors GitHub Issues and automatically generates pull requests with working code implementations.\\n\\n## Technical Implementation\\n- Integrates with GitHub API for issue tracking\\n- Uses Claude/GPT for code generation\\n- Implements automated testing and validation\\n- Handles PR creation and code review workflows\\n\\n## Impact\\n- Demonstrates practical agent architecture patterns\\n- Reduces time from issue creation to implementation\\n- Open source tool for developer productivity","technologies":["Python","GitHub API","Claude","GPT","Autonomous Agents"],"featured":true,"order":1,"team":null,"live_url":"https://github.com/johnhkchen/my-little-soda","case_study_url":null,"category":"open-source"}	{"category":"open-source"}	\N	\N
114	126	work_projects	2	{"id":2,"status":"published","title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Co-Founder & Treasurer","year":"2022-2024","duration":"2 years","description":"Founded and led CS Club, helping students transfer to top universities including UC Berkeley. Built community site and organized 100+ tech events.","content":"## Overview\\n\\nCo-founded and managed CS Club at CCSF, creating a thriving community that helped students succeed in tech careers.\\n\\n## Achievements\\n- **Student Success**: 2 consecutive years of students transferring to UC Berkeley\\n- **Events**: Organized 100+ hackathons, workshops, and tech meetups\\n- **Education**: Introduced students to Astro, helping them build professional portfolios\\n- **Community Site**: Built https://ccsf-cs.club for resources and announcements\\n\\n## Impact\\n- Mentored first-time hackathon participants\\n- Connected students with SF tech community\\n- Created pathways for non-traditional students into tech careers","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":2,"team":null,"live_url":"https://ccsf-cs.club","case_study_url":null,"category":"education"}	{"category":"education"}	\N	\N
149	175	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:37:39.275Z","title":"v0 to Production","published":true,"content":"v0.dev gives you a template. Claude Code makes it production-ready.\\n\\n## The Problem Space\\n\\nYou have a beautiful UI template. You need it to work with real data, deploy to production, and allow non-developers to update content. Traditional tutorials show you *what* to build. This shows you *how to prompt* an AI to build it.\\n\\n## The Prompt Framework\\n\\n### 1. Start with Constraints, Not Solutions\\n\\n**Don't prompt:** \\"Build me an API with Express\\"\\n\\n**Do prompt:** \\"I need to connect this Astro frontend to Directus. What's the lightest-weight option that maintains type safety?\\"\\n\\nClaude Code suggested Hono (12KB vs Express's 200KB+). I wouldn't have known it existed.\\n\\nThe pattern: **State the problem and constraints. Let the AI propose solutions.**\\n\\n### 2. Ask for Architectural Decisions\\n\\n**The prompt:**\\n> \\"I'm building a portfolio site. I need it to be fast, SEO-friendly, support markdown content, and allow my partner to update projects without touching code. What stack would you recommend?\\"\\n\\n**Claude Code's response:**\\n- Astro (content-first, minimal JavaScript)\\n- Hono API layer (type-safe, lightweight)\\n- Directus CMS (best admin UI, PostgreSQL-backed)\\n- Docker Compose (reproducible environments)\\n\\nI asked *why* for each choice. The explanations taught me trade-offs I'd have spent hours researching.\\n\\n**The insight:** AI has context on the entire ecosystem. Use it as an architecture advisor.\\n\\n### 3. Iterate on \\"Show Me How\\"\\n\\nInstead of asking for complete implementations, request incremental examples:\\n\\n**Progression:**\\n1. \\"Show me how to set up the Directus TypeScript client\\"\\n2. \\"Now show me how to fetch a single work project by slug\\"\\n3. \\"How do I make this work with Astro's content collection pattern?\\"\\n\\nEach step builds on the last. Each answer includes code I can verify works before moving forward.\\n\\n**Why this matters:** You stay in control. You understand each piece before adding complexity.\\n\\n### 4. Prompt for Type Safety Chains\\n\\n**The prompt that changed everything:**\\n> \\"I want TypeScript to catch errors if I misspell a field name anywhere from Directus to the frontend. How do I structure this?\\"\\n\\nClaude Code designed the entire type safety chain:\\n- Directus schema interfaces\\n- API layer types that mirror them\\n- Frontend types that match API responses\\n- Astro components with full autocomplete\\n\\nOne prompt. Twenty minutes of work. Production-grade type safety.\\n\\n### 5. Ask \\"What Would Go Wrong?\\"\\n\\nAfter implementing a feature:\\n\\n**The prompt:**\\n> \\"I have Docker services for Directus, API, and frontend. What could go wrong in production?\\"\\n\\n**Claude Code's response:**\\n- Services might start in wrong order → Add healthchecks\\n- Network isolation issues → Use same Docker network\\n- Race conditions on startup → Add `depends_on` with conditions\\n\\nThis is defensive architecture from a single question.\\n\\n## The Workflow in Practice\\n\\n### Real Session Example: Adding the Content Adapter\\n\\n**Me:** \\"Astro expects content collections. Directus is an API. How do I bridge them?\\"\\n\\n**Claude Code:** \\"Use an adapter pattern. Here's the structure...\\"\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  return {\\n    slug: project.slug,\\n    data: { /* transformed to Astro format */ }\\n  }\\n}\\n```\\n\\n**Me:** \\"Why this approach vs directly calling Directus from Astro?\\"\\n\\n**Claude Code:** \\"Security boundary, type safety, easy to swap CMS later. If you outgrow Directus, rewrite this one file.\\"\\n\\n**The pattern:** Request implementation → Understand trade-offs → Iterate if needed.\\n\\n## What Makes This Reproducible\\n\\n### 1. You Don't Need to Know the Ecosystem\\n\\nI'd never used Hono. Barely knew Directus. Claude Code:\\n- Suggested them based on requirements\\n- Showed exactly how to use them\\n- Explained when I'd outgrow them\\n\\n**The unlock:** Prompt with your constraints, not your assumptions.\\n\\n### 2. It's Not Magic; It's Methodology\\n\\nThe workflow:\\n1. Define what you need (content updates without deployments)\\n2. State your constraints (self-hosted, type-safe, fast)\\n3. Ask for recommendations\\n4. Request implementations with explanations\\n5. Iterate when you hit edge cases\\n\\nAnyone can follow this. The code changes. The approach doesn't.\\n\\n### 3. You Stay in the Driver's Seat\\n\\nI made every architectural decision. Claude Code provided:\\n- Options with trade-offs\\n- Implementation details\\n- \\"Here's what could break\\" analysis\\n\\nI still chose Cloudflare Tunnels over nginx. Still decided on Docker Compose over Kubernetes. Still picked PostgreSQL over MongoDB.\\n\\n**The difference:** Those decisions took minutes instead of days of research.\\n\\n## The Meta-Lesson\\n\\n### Traditional Approach\\n1. Research stack options (days)\\n2. Read documentation (days)\\n3. Set up boilerplate (hours)\\n4. Debug integration issues (days)\\n5. Discover you chose wrong tools (restart)\\n\\n**Estimated time:** 2-4 weeks for production-ready\\n\\n### AI-Assisted Approach\\n1. Describe requirements and constraints\\n2. Evaluate AI-proposed architecture\\n3. Implement incrementally with AI guidance\\n4. Ask \\"what breaks?\\" at each step\\n5. Deploy with AI-generated configs\\n\\n**Actual time:** 10 hours active work\\n\\n### What Changed\\n\\nNot the fundamentals. Astro is still Astro. Docker is still Docker. TypeScript is still TypeScript.\\n\\nWhat changed: **No more guessing which tools fit together.** No more reading docs for tools you won't use.\\n\\n## The Limitations\\n\\n### Where AI Excels\\n- Architecture recommendations based on constraints\\n- Boilerplate and integration code\\n- Type system design\\n- Configuration files\\n- \\"What could break?\\" analysis\\n\\n### Where You Still Decide\\n- Content strategy (what's worth showing?)\\n- Design choices (minimalism vs maximalism)\\n- Accuracy of content (AI writes well, verify facts)\\n- When to ship (perfect vs good enough)\\n\\n### What You Still Learn\\n\\nI now understand:\\n- Why type safety matters across boundaries\\n- When Docker healthchecks prevent race conditions\\n- How content adapters enable flexibility\\n\\nI didn't just get a working site. I learned architecture patterns I'll use again.\\n\\n## How to Apply This\\n\\n### Starting a New Project\\n\\n**Step 1:** Write a constraint prompt\\n```\\nI need a [type of site] that:\\n- [Performance requirement]\\n- [Content management need]\\n- [Deployment constraint]\\n- [Team skill level]\\n\\nWhat stack would work?\\n```\\n\\n**Step 2:** For each suggested tool, ask:\\n- \\"Why this over [alternative]?\\"\\n- \\"When would I outgrow this?\\"\\n- \\"Show me the integration points\\"\\n\\n**Step 3:** Implement incrementally\\n- Request one feature at a time\\n- Verify it works before adding complexity\\n- Ask \\"what breaks?\\" after each addition\\n\\n**Step 4:** Iterate on rough edges\\n- \\"This works but feels brittle. How do I make it production-ready?\\"\\n- \\"What am I missing for error handling?\\"\\n\\n### The Results\\n\\n**Live:** https://b28.dev\\n\\n**Built in:** 10 hours active work\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Type-safe:** Yes\\n\\n**Self-hosted:** Yes\\n\\n**CMS-backed:** Yes\\n\\n**Could you reproduce this?** Yes. Use the same prompt framework.\\n\\n## The Real Insight\\n\\n2023: You needed to know the ecosystem to build production sites.\\n\\n2025: You need to know how to *describe what you want* and *evaluate options*.\\n\\nThe tools haven't changed. Your workflow has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Methodology:** Constraint-based prompting + incremental implementation + \\"what breaks?\\" analysis\\n"}	{"title":"v0 to Production","content":"v0.dev gives you a template. Claude Code makes it production-ready.\\n\\n## The Problem Space\\n\\nYou have a beautiful UI template. You need it to work with real data, deploy to production, and allow non-developers to update content. Traditional tutorials show you *what* to build. This shows you *how to prompt* an AI to build it.\\n\\n## The Prompt Framework\\n\\n### 1. Start with Constraints, Not Solutions\\n\\n**Don't prompt:** \\"Build me an API with Express\\"\\n\\n**Do prompt:** \\"I need to connect this Astro frontend to Directus. What's the lightest-weight option that maintains type safety?\\"\\n\\nClaude Code suggested Hono (12KB vs Express's 200KB+). I wouldn't have known it existed.\\n\\nThe pattern: **State the problem and constraints. Let the AI propose solutions.**\\n\\n### 2. Ask for Architectural Decisions\\n\\n**The prompt:**\\n> \\"I'm building a portfolio site. I need it to be fast, SEO-friendly, support markdown content, and allow my partner to update projects without touching code. What stack would you recommend?\\"\\n\\n**Claude Code's response:**\\n- Astro (content-first, minimal JavaScript)\\n- Hono API layer (type-safe, lightweight)\\n- Directus CMS (best admin UI, PostgreSQL-backed)\\n- Docker Compose (reproducible environments)\\n\\nI asked *why* for each choice. The explanations taught me trade-offs I'd have spent hours researching.\\n\\n**The insight:** AI has context on the entire ecosystem. Use it as an architecture advisor.\\n\\n### 3. Iterate on \\"Show Me How\\"\\n\\nInstead of asking for complete implementations, request incremental examples:\\n\\n**Progression:**\\n1. \\"Show me how to set up the Directus TypeScript client\\"\\n2. \\"Now show me how to fetch a single work project by slug\\"\\n3. \\"How do I make this work with Astro's content collection pattern?\\"\\n\\nEach step builds on the last. Each answer includes code I can verify works before moving forward.\\n\\n**Why this matters:** You stay in control. You understand each piece before adding complexity.\\n\\n### 4. Prompt for Type Safety Chains\\n\\n**The prompt that changed everything:**\\n> \\"I want TypeScript to catch errors if I misspell a field name anywhere from Directus to the frontend. How do I structure this?\\"\\n\\nClaude Code designed the entire type safety chain:\\n- Directus schema interfaces\\n- API layer types that mirror them\\n- Frontend types that match API responses\\n- Astro components with full autocomplete\\n\\nOne prompt. Twenty minutes of work. Production-grade type safety.\\n\\n### 5. Ask \\"What Would Go Wrong?\\"\\n\\nAfter implementing a feature:\\n\\n**The prompt:**\\n> \\"I have Docker services for Directus, API, and frontend. What could go wrong in production?\\"\\n\\n**Claude Code's response:**\\n- Services might start in wrong order → Add healthchecks\\n- Network isolation issues → Use same Docker network\\n- Race conditions on startup → Add `depends_on` with conditions\\n\\nThis is defensive architecture from a single question.\\n\\n## The Workflow in Practice\\n\\n### Real Session Example: Adding the Content Adapter\\n\\n**Me:** \\"Astro expects content collections. Directus is an API. How do I bridge them?\\"\\n\\n**Claude Code:** \\"Use an adapter pattern. Here's the structure...\\"\\n\\n```typescript\\n// frontend/src/content/index.ts\\nexport async function getWorkProject(slug: string) {\\n  const response = await api.getWorkProject(slug)\\n  if (!response?.data) return null\\n\\n  return {\\n    slug: project.slug,\\n    data: { /* transformed to Astro format */ }\\n  }\\n}\\n```\\n\\n**Me:** \\"Why this approach vs directly calling Directus from Astro?\\"\\n\\n**Claude Code:** \\"Security boundary, type safety, easy to swap CMS later. If you outgrow Directus, rewrite this one file.\\"\\n\\n**The pattern:** Request implementation → Understand trade-offs → Iterate if needed.\\n\\n## What Makes This Reproducible\\n\\n### 1. You Don't Need to Know the Ecosystem\\n\\nI'd never used Hono. Barely knew Directus. Claude Code:\\n- Suggested them based on requirements\\n- Showed exactly how to use them\\n- Explained when I'd outgrow them\\n\\n**The unlock:** Prompt with your constraints, not your assumptions.\\n\\n### 2. It's Not Magic; It's Methodology\\n\\nThe workflow:\\n1. Define what you need (content updates without deployments)\\n2. State your constraints (self-hosted, type-safe, fast)\\n3. Ask for recommendations\\n4. Request implementations with explanations\\n5. Iterate when you hit edge cases\\n\\nAnyone can follow this. The code changes. The approach doesn't.\\n\\n### 3. You Stay in the Driver's Seat\\n\\nI made every architectural decision. Claude Code provided:\\n- Options with trade-offs\\n- Implementation details\\n- \\"Here's what could break\\" analysis\\n\\nI still chose Cloudflare Tunnels over nginx. Still decided on Docker Compose over Kubernetes. Still picked PostgreSQL over MongoDB.\\n\\n**The difference:** Those decisions took minutes instead of days of research.\\n\\n## The Meta-Lesson\\n\\n### Traditional Approach\\n1. Research stack options (days)\\n2. Read documentation (days)\\n3. Set up boilerplate (hours)\\n4. Debug integration issues (days)\\n5. Discover you chose wrong tools (restart)\\n\\n**Estimated time:** 2-4 weeks for production-ready\\n\\n### AI-Assisted Approach\\n1. Describe requirements and constraints\\n2. Evaluate AI-proposed architecture\\n3. Implement incrementally with AI guidance\\n4. Ask \\"what breaks?\\" at each step\\n5. Deploy with AI-generated configs\\n\\n**Actual time:** 10 hours active work\\n\\n### What Changed\\n\\nNot the fundamentals. Astro is still Astro. Docker is still Docker. TypeScript is still TypeScript.\\n\\nWhat changed: **No more guessing which tools fit together.** No more reading docs for tools you won't use.\\n\\n## The Limitations\\n\\n### Where AI Excels\\n- Architecture recommendations based on constraints\\n- Boilerplate and integration code\\n- Type system design\\n- Configuration files\\n- \\"What could break?\\" analysis\\n\\n### Where You Still Decide\\n- Content strategy (what's worth showing?)\\n- Design choices (minimalism vs maximalism)\\n- Accuracy of content (AI writes well, verify facts)\\n- When to ship (perfect vs good enough)\\n\\n### What You Still Learn\\n\\nI now understand:\\n- Why type safety matters across boundaries\\n- When Docker healthchecks prevent race conditions\\n- How content adapters enable flexibility\\n\\nI didn't just get a working site. I learned architecture patterns I'll use again.\\n\\n## How to Apply This\\n\\n### Starting a New Project\\n\\n**Step 1:** Write a constraint prompt\\n```\\nI need a [type of site] that:\\n- [Performance requirement]\\n- [Content management need]\\n- [Deployment constraint]\\n- [Team skill level]\\n\\nWhat stack would work?\\n```\\n\\n**Step 2:** For each suggested tool, ask:\\n- \\"Why this over [alternative]?\\"\\n- \\"When would I outgrow this?\\"\\n- \\"Show me the integration points\\"\\n\\n**Step 3:** Implement incrementally\\n- Request one feature at a time\\n- Verify it works before adding complexity\\n- Ask \\"what breaks?\\" after each addition\\n\\n**Step 4:** Iterate on rough edges\\n- \\"This works but feels brittle. How do I make it production-ready?\\"\\n- \\"What am I missing for error handling?\\"\\n\\n### The Results\\n\\n**Live:** https://b28.dev\\n\\n**Built in:** 10 hours active work\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Type-safe:** Yes\\n\\n**Self-hosted:** Yes\\n\\n**CMS-backed:** Yes\\n\\n**Could you reproduce this?** Yes. Use the same prompt framework.\\n\\n## The Real Insight\\n\\n2023: You needed to know the ecosystem to build production sites.\\n\\n2025: You need to know how to *describe what you want* and *evaluate options*.\\n\\nThe tools haven't changed. Your workflow has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Methodology:** Constraint-based prompting + incremental implementation + \\"what breaks?\\" analysis\\n","date_updated":"2025-10-14T06:37:39.275Z"}	\N	\N
115	127	work_projects	3	{"id":3,"status":"published","title":"Tech Event Analyzer - Hackathon Project","slug":"tech-event-analyzer","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"Discovered Lu.ma pagination API vulnerability and built analyzer to identify which tech companies consistently provide food at events. Found Cloudflare, AWS, and GitHub as top sponsors.","content":"## Problem\\n\\nTech event attendees need to know which events are worth attending beyond just the topic.\\n\\n## Solution\\n\\nBuilt a scraper and analyzer that:\\n- Discovered and utilized undocumented Lu.ma pagination API\\n- Extracted event data including sponsors and amenities\\n- Identified patterns in sponsor behavior\\n- Ranked companies by event quality metrics\\n\\n## Key Findings\\n- Cloudflare, AWS, and GitHub consistently budget for attendee food\\n- Correlation between food quality and event engagement\\n- Useful for event planning and attendee decision-making\\n\\n## Technologies\\n- API reverse engineering\\n- Data analysis and visualization\\n- Pattern recognition","technologies":["Python","API Scraping","Data Analysis","Lu.ma"],"featured":true,"order":3,"team":null,"live_url":null,"case_study_url":null,"category":"hackathon"}	{"category":"hackathon"}	\N	\N
116	128	work_projects	4	{"id":4,"status":"published","title":"SF Legacy Business Registry - Civic Tech","slug":"sf-legacy-business-registry","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"8 hours","description":"Built PDF-to-structured-data pipeline using LlamaParse to transform San Francisco legacy business applications into an engaging, searchable database.","content":"## Problem\\n\\nSan Francisco's legacy business data was trapped in PDF application forms, making it difficult to discover and explore the city's historic businesses.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Used LlamaParse to extract structured data from PDF applications\\n- Cleaned and normalized business information\\n- Built searchable database with rich metadata\\n\\n### User Experience\\n- Created engaging visual interface for browsing businesses\\n- Added filtering by neighborhood, business type, and year established\\n- Implemented search functionality\\n\\n## Impact\\n- Made civic data accessible and useful\\n- Demonstrated practical LLM applications for document processing\\n- Created reusable pipeline for similar civic tech projects\\n\\n## Tech Stack\\n- LlamaParse for PDF extraction\\n- Vector search for semantic queries\\n- Modern web framework for UI","technologies":["LlamaParse","PDF Processing","Civic Tech","Vector Search","Full Stack"],"featured":true,"order":4,"team":null,"live_url":null,"case_study_url":null,"category":"hackathon"}	{"category":"hackathon"}	\N	\N
117	129	work_projects	5	{"id":5,"status":"published","title":"Piper - STEM Learning Platform","slug":"piper","company":"Piper, Inc.","role":"Software Engineer","year":"2018-2021","duration":"3 years 5 months","description":"Shipped expansion pack that increased customer LTV by 25%. Built analytics infrastructure, FERPA-compliant survey system, and technical blog content.","content":"## Role & Responsibilities\\n\\nFull-stack engineer on Python-based STEM learning game for K-12 education.\\n\\n## Key Achievements\\n\\n### Product Development\\n- **Expansion Pack**: Shipped major release increasing customer LTV by 25%\\n- **Map Converter**: Built forward-compatible Python tool enabling new visual and mechanical game features\\n- **Technical Writing**: Created blog series exploring CS and EE concepts through DIY projects\\n\\n### Infrastructure & Analytics\\n- **Analytics Dashboard**: Set up SQL and Amplitude for marketing, QA, and dev-ops intelligence\\n- **Survey System**: Developed FERPA-compliant web service using JavaScript, Google Apps Engine, and Firebase\\n\\n## Impact\\n- Directly contributed to revenue growth\\n- Improved development workflow and tooling\\n- Enhanced data-driven decision making","technologies":["Python","JavaScript","SQL","Firebase","Google Apps Engine","Amplitude","Game Development"],"featured":true,"order":5,"team":null,"live_url":null,"case_study_url":null,"category":"employment"}	{"category":"employment"}	\N	\N
118	130	work_projects	6	{"id":6,"status":"published","title":"IdeaWall - HCI Research","slug":"ideawall-research","company":"UC Davis Visualization Lab","role":"Research Assistant","year":"2015-2016","duration":"1 year 2 months","description":"Co-authored ACM CSCW paper on AI-augmented creative collaboration. Built real-time system extracting discussion insights and providing combinatorial visual stimuli.","content":"## Research Project\\n\\n**Published**: ACM Conference on Computer Supported Cooperative Work and Social Computing (CSCW '17)\\n\\n## Overview\\n\\nDeveloped IdeaWall, an intelligent system that augments verbal creative collaboration with real-time visual stimuli.\\n\\n## Technical Implementation\\n- Real-time speech processing and information extraction\\n- Web search integration for contextual materials\\n- Visual display system with three cognitive strategies\\n- User study with 24 participants across 12 groups\\n\\n## Research Contributions\\n- Demonstrated effectiveness of AI-assisted collaboration tools\\n- Validated three cognitive strategies for visual facilitation\\n- Set foundation for future intelligent groupware systems\\n\\n## Skills Developed\\n- Research methodology and user testing\\n- Technical writing for academic publication\\n- Data visualization and analysis\\n- Human-computer interaction design","technologies":["HCI Research","Real-time Processing","User Studies","Data Visualization","Academic Writing"],"featured":true,"order":6,"team":null,"live_url":null,"case_study_url":"http://dl.acm.org/citation.cfm?id=2998208","category":"research"}	{"category":"research"}	\N	\N
119	131	work_projects	7	{"id":7,"status":"published","title":"Fitness Planner - Vector Search Application","slug":"fitness-planner","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"AI-powered fitness routine suggester using Weaviate vector database. Transforms user descriptions into personalized workout plans.","content":"## Concept\\n\\nNatural language fitness planning: describe your goals and fitness level, get personalized workout routines.\\n\\n## Technical Implementation\\n\\n### Vector Search\\n- Used Weaviate for semantic workout search\\n- Embedded fitness routines with descriptions\\n- Implemented semantic similarity matching\\n\\n### Example Queries\\n- \\"out of shape 30 year old couch to 5k\\"\\n- \\"strength training for beginners\\"\\n- \\"low impact cardio for seniors\\"\\n\\n### Structured Output\\n- Generated progressive workout plans\\n- Included exercise descriptions and modifications\\n- Suggested timelines and milestones\\n\\n## Learning\\n- Practical vector database implementation\\n- Semantic search for recommendation systems\\n- Rapid prototyping with modern AI tools","technologies":["Weaviate","Vector Search","LLM","Full Stack","RAG"],"featured":true,"order":7,"team":null,"live_url":null,"case_study_url":null,"category":"hackathon"}	{"category":"hackathon"}	\N	\N
141	162	skills	18	{"id":18,"name":"Tailwind CSS","category":"frontend","proficiency":"expert","order":18,"featured":false}	{"featured":false}	\N	\N
150	176	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:41:33.771Z","title":"Building Production Sites with AI: How Accumulated Knowledge Becomes Execution","published":true,"content":"# Building Production Sites with AI: How Accumulated Knowledge Becomes Execution\\n\\nThis isn't a \\"10 hours from zero to production\\" story. This is about learning gradually, recognizing when you're ready, and executing fast because you built the foundation.\\n\\n## The Real Timeline\\n\\n**Months before:** Experimenting with Claude Code. Asking about containers. Trying to understand web frameworks. Getting suggestions for tools I didn't have time to integrate yet.\\n\\n**The moment:** Sonnet 4.5 releases. I realize: I'm ready. All those scattered learnings can finally come together.\\n\\n**The execution:** 10 hours of active work to build the portfolio. Not because AI is magic, but because I'd been learning the pieces for months.\\n\\n## How Learning Accumulates\\n\\n### Phase 1: Curiosity Without Application\\n\\nEarly conversations with Claude Code:\\n\\n**Me:** \\"What's the difference between Docker Compose and Kubernetes?\\"\\n\\n**Claude Code:** Explains orchestration, when you need each, complexity trade-offs.\\n\\nI file this away. Don't use it immediately. But now I know Docker Compose exists.\\n\\n---\\n\\n**Me:** \\"Why would I use a headless CMS instead of just markdown files?\\"\\n\\n**Claude Code:** Explains non-technical editors, API flexibility, content reuse.\\n\\nAnother piece filed away. Maybe useful later.\\n\\n---\\n\\n**Me:** \\"What makes TypeScript worth the setup overhead?\\"\\n\\n**Claude Code:** Type safety at boundaries, catching errors at build time, better tooling.\\n\\nI start to see patterns forming.\\n\\n### Phase 2: Connecting the Dots\\n\\nMonths later, different conversation:\\n\\n**Me:** \\"I keep seeing Astro mentioned. What's the point if I already know React?\\"\\n\\n**Claude Code:** Content-first architecture, zero JavaScript by default, better for portfolios than full SPAs.\\n\\nThis connects to the \\"static vs dynamic\\" conversation from two months ago.\\n\\n---\\n\\n**Me:** \\"Everyone uses Express for Node APIs. Is there a reason to use anything else?\\"\\n\\n**Claude Code:** For lightweight APIs, Hono is 12KB vs 200KB. Edge-ready, better TypeScript DX.\\n\\nI remember the \\"keep it simple\\" advice from earlier. This fits.\\n\\n### Phase 3: The Synthesis Moment\\n\\nSonnet 4.5 drops. I decide: time to build the portfolio.\\n\\nNow, instead of asking \\"How do I build a portfolio?\\", I can ask:\\n\\n> \\"I have an Astro site from v0.dev. I want Directus for content, a lightweight API layer, type safety across the stack, and Docker deployment. Based on what we've discussed before, what's the integration approach?\\"\\n\\nClaude Code doesn't need to convince me of the tools. We've already explored them. It jumps straight to implementation.\\n\\n**This is the unlock:** Accumulated context lets you move fast.\\n\\n## What This Actually Looks Like\\n\\n### Without Foundation (How I Started)\\n\\n**Me:** \\"Build me a portfolio site\\"\\n\\n**Claude Code:** \\"Here's a Next.js app with...\\"\\n\\n**Me:** \\"Why Next.js?\\"\\n\\n**Claude Code:** Explains SSR, routing, ecosystem...\\n\\n**Me:** \\"What's SSR?\\"\\n\\nI'm learning fundamentals while trying to build. Slow.\\n\\n### With Foundation (How It Ended)\\n\\n**Me:** \\"Astro frontend, Directus CMS, Hono API. Show me the content adapter pattern.\\"\\n\\n**Claude Code:** *Shows implementation*\\n\\n**Me:** \\"Type safety chain across all three?\\"\\n\\n**Claude Code:** *Shows TypeScript interfaces*\\n\\nI already understand SSR, why Astro, why Directus, what an API layer does. We're discussing implementation, not fundamentals.\\n\\n## The Methodology That Emerged\\n\\nOver months of exploration, these patterns became clear:\\n\\n### 1. Ask About Trade-offs, Not Just \\"How\\"\\n\\nEarly on, I'd ask: \\"How do I deploy this?\\"\\n\\nNow I ask: \\"I'm choosing between nginx reverse proxy and Cloudflare Tunnels. What am I trading off?\\"\\n\\nThe shift: From \\"teach me to do it\\" to \\"help me decide.\\"\\n\\n### 2. Explore Before You Need\\n\\nI asked about Directus six months before building this site. When the moment came, I knew it was the right tool.\\n\\n**The pattern:** Curiosity-driven learning builds a mental toolkit. When you need something, you already know it exists.\\n\\n### 3. Recognize When You're Ready\\n\\nThe signal: You stop asking \\"What should I use?\\" and start asking \\"How do I integrate these specific things?\\"\\n\\nFor me, that moment was realizing I could name the stack I wanted without Claude Code suggesting it.\\n\\n### 4. Execute Fast on Familiar Ground\\n\\nWith the foundation built, implementation is fast:\\n- I know why Docker Compose over Kubernetes\\n- I know why Hono over Express\\n- I know why Directus over Strapi\\n- I know what type safety buys me\\n\\nClaude Code handles syntax and configuration. I handle architecture.\\n\\n## What Makes This Reproducible\\n\\n### The Patient Approach\\n\\n1. **Explore without deadline** - Ask about tools when you see them mentioned, even if you don't need them yet\\n2. **Connect conversations** - \\"You mentioned X last month. How does that relate to Y?\\"\\n3. **Build mental models** - Not just \\"how to use Docker\\" but \\"when Docker Compose vs Kubernetes\\"\\n4. **Recognize readiness** - When you stop needing tool suggestions, you're ready to build\\n\\n### The Fast Execution\\n\\nWhen the moment comes:\\n1. You already know the stack\\n2. AI handles integration details\\n3. You make architectural decisions in minutes (because you explored trade-offs months ago)\\n4. 10 hours of active work produces production-ready code\\n\\n**Why this is honest:** The 10 hours is real. But it's built on months of foundation.\\n\\n## The Sonnet 4.5 Catalyst\\n\\nWhy did this finally happen when Sonnet 4.5 released?\\n\\n**Better at synthesis:** Earlier models could explain tools. Sonnet 4.5 could integrate multiple tools I'd learned about separately.\\n\\n**Longer context:** It could reference patterns we'd discussed in earlier conversations, even if I didn't explicitly mention them.\\n\\n**Confidence:** I'd watched the models improve. When Sonnet 4.5 dropped, I knew it could handle the complexity I'd been accumulating knowledge for.\\n\\n**The moment:** Not \\"AI got good enough to build this.\\" But \\"I got ready, and the AI was ready too.\\"\\n\\n## What You Actually Learn\\n\\nThis process teaches:\\n\\n**Technical:**\\n- Why type safety matters at boundaries\\n- When Docker healthchecks prevent race conditions\\n- How content adapters enable flexibility\\n\\n**Strategic:**\\n- Recognizing tool fatigue (Express works, but do I need all of it?)\\n- Understanding trade-off spaces (VPS vs serverless vs homelab)\\n- Knowing when \\"good enough\\" beats \\"perfect\\"\\n\\n**Workflow:**\\n- Building mental toolkits over time\\n- Asking better questions as you learn\\n- Executing fast when foundation is solid\\n\\n## The Honest Timeline\\n\\n**Months 1-3:** Confused. Asking basic questions. Getting overwhelmed by options.\\n\\n**Months 4-6:** Patterns emerging. Starting to see why people choose certain tools.\\n\\n**Month 7:** Sonnet 4.5 releases. I realize I can name the stack I want.\\n\\n**Week 8:** 10 hours active work. Production site live.\\n\\n**The truth:** You can't skip to week 8. But you can accelerate months 1-7 by exploring deliberately.\\n\\n## How to Apply This\\n\\n### If You're Starting Now\\n\\n**Month 1:** Ask about fundamentals\\n- \\"Why use a framework vs vanilla JS?\\"\\n- \\"What problems do ORMs solve?\\"\\n- \\"When do I need Docker?\\"\\n\\nDon't build anything yet. Just understand the problem spaces.\\n\\n**Month 2:** Explore specific tools\\n- \\"I keep seeing Astro. What's it for?\\"\\n- \\"Why would I use Hono over Express?\\"\\n- \\"What's the deal with Directus?\\"\\n\\nFile away the answers. You might not use them for months.\\n\\n**Month 3:** Connect the dots\\n- \\"If I use Astro + Directus, how do they talk?\\"\\n- \\"What's the type safety story across that boundary?\\"\\n- \\"How does Docker fit into this?\\"\\n\\nNow you're thinking in systems.\\n\\n**Month 4:** You're ready\\n- You can describe what you want without asking for tool suggestions\\n- You ask \\"how do I integrate X and Y\\" not \\"what should I use\\"\\n- Execution is fast because decisions are already made\\n\\n### The Pattern\\n\\n**Explore → Connect → Recognize → Execute**\\n\\nThis portfolio represents: 6 months exploring, 1 moment recognizing, 10 hours executing.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Timeline:**\\n- 6 months learning with Claude Code\\n- 1 \\"I'm ready\\" moment when Sonnet 4.5 dropped\\n- 10 hours active implementation\\n\\n**Could you reproduce this?** Yes. But give yourself time to learn the pieces first.\\n\\n## The Real Insight\\n\\n**2023:** You needed to know the ecosystem before starting.\\n\\n**2025:** You can learn the ecosystem *through conversation*, accumulate knowledge gradually, then execute fast when ready.\\n\\n**The unlock:** AI as a patient teacher over months, then a fast collaborator when you're prepared.\\n\\nThe tools haven't changed. The learning curve has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Patient exploration → Gradual synthesis → Rapid execution when ready\\n"}	{"title":"Building Production Sites with AI: How Accumulated Knowledge Becomes Execution","content":"# Building Production Sites with AI: How Accumulated Knowledge Becomes Execution\\n\\nThis isn't a \\"10 hours from zero to production\\" story. This is about learning gradually, recognizing when you're ready, and executing fast because you built the foundation.\\n\\n## The Real Timeline\\n\\n**Months before:** Experimenting with Claude Code. Asking about containers. Trying to understand web frameworks. Getting suggestions for tools I didn't have time to integrate yet.\\n\\n**The moment:** Sonnet 4.5 releases. I realize: I'm ready. All those scattered learnings can finally come together.\\n\\n**The execution:** 10 hours of active work to build the portfolio. Not because AI is magic, but because I'd been learning the pieces for months.\\n\\n## How Learning Accumulates\\n\\n### Phase 1: Curiosity Without Application\\n\\nEarly conversations with Claude Code:\\n\\n**Me:** \\"What's the difference between Docker Compose and Kubernetes?\\"\\n\\n**Claude Code:** Explains orchestration, when you need each, complexity trade-offs.\\n\\nI file this away. Don't use it immediately. But now I know Docker Compose exists.\\n\\n---\\n\\n**Me:** \\"Why would I use a headless CMS instead of just markdown files?\\"\\n\\n**Claude Code:** Explains non-technical editors, API flexibility, content reuse.\\n\\nAnother piece filed away. Maybe useful later.\\n\\n---\\n\\n**Me:** \\"What makes TypeScript worth the setup overhead?\\"\\n\\n**Claude Code:** Type safety at boundaries, catching errors at build time, better tooling.\\n\\nI start to see patterns forming.\\n\\n### Phase 2: Connecting the Dots\\n\\nMonths later, different conversation:\\n\\n**Me:** \\"I keep seeing Astro mentioned. What's the point if I already know React?\\"\\n\\n**Claude Code:** Content-first architecture, zero JavaScript by default, better for portfolios than full SPAs.\\n\\nThis connects to the \\"static vs dynamic\\" conversation from two months ago.\\n\\n---\\n\\n**Me:** \\"Everyone uses Express for Node APIs. Is there a reason to use anything else?\\"\\n\\n**Claude Code:** For lightweight APIs, Hono is 12KB vs 200KB. Edge-ready, better TypeScript DX.\\n\\nI remember the \\"keep it simple\\" advice from earlier. This fits.\\n\\n### Phase 3: The Synthesis Moment\\n\\nSonnet 4.5 drops. I decide: time to build the portfolio.\\n\\nNow, instead of asking \\"How do I build a portfolio?\\", I can ask:\\n\\n> \\"I have an Astro site from v0.dev. I want Directus for content, a lightweight API layer, type safety across the stack, and Docker deployment. Based on what we've discussed before, what's the integration approach?\\"\\n\\nClaude Code doesn't need to convince me of the tools. We've already explored them. It jumps straight to implementation.\\n\\n**This is the unlock:** Accumulated context lets you move fast.\\n\\n## What This Actually Looks Like\\n\\n### Without Foundation (How I Started)\\n\\n**Me:** \\"Build me a portfolio site\\"\\n\\n**Claude Code:** \\"Here's a Next.js app with...\\"\\n\\n**Me:** \\"Why Next.js?\\"\\n\\n**Claude Code:** Explains SSR, routing, ecosystem...\\n\\n**Me:** \\"What's SSR?\\"\\n\\nI'm learning fundamentals while trying to build. Slow.\\n\\n### With Foundation (How It Ended)\\n\\n**Me:** \\"Astro frontend, Directus CMS, Hono API. Show me the content adapter pattern.\\"\\n\\n**Claude Code:** *Shows implementation*\\n\\n**Me:** \\"Type safety chain across all three?\\"\\n\\n**Claude Code:** *Shows TypeScript interfaces*\\n\\nI already understand SSR, why Astro, why Directus, what an API layer does. We're discussing implementation, not fundamentals.\\n\\n## The Methodology That Emerged\\n\\nOver months of exploration, these patterns became clear:\\n\\n### 1. Ask About Trade-offs, Not Just \\"How\\"\\n\\nEarly on, I'd ask: \\"How do I deploy this?\\"\\n\\nNow I ask: \\"I'm choosing between nginx reverse proxy and Cloudflare Tunnels. What am I trading off?\\"\\n\\nThe shift: From \\"teach me to do it\\" to \\"help me decide.\\"\\n\\n### 2. Explore Before You Need\\n\\nI asked about Directus six months before building this site. When the moment came, I knew it was the right tool.\\n\\n**The pattern:** Curiosity-driven learning builds a mental toolkit. When you need something, you already know it exists.\\n\\n### 3. Recognize When You're Ready\\n\\nThe signal: You stop asking \\"What should I use?\\" and start asking \\"How do I integrate these specific things?\\"\\n\\nFor me, that moment was realizing I could name the stack I wanted without Claude Code suggesting it.\\n\\n### 4. Execute Fast on Familiar Ground\\n\\nWith the foundation built, implementation is fast:\\n- I know why Docker Compose over Kubernetes\\n- I know why Hono over Express\\n- I know why Directus over Strapi\\n- I know what type safety buys me\\n\\nClaude Code handles syntax and configuration. I handle architecture.\\n\\n## What Makes This Reproducible\\n\\n### The Patient Approach\\n\\n1. **Explore without deadline** - Ask about tools when you see them mentioned, even if you don't need them yet\\n2. **Connect conversations** - \\"You mentioned X last month. How does that relate to Y?\\"\\n3. **Build mental models** - Not just \\"how to use Docker\\" but \\"when Docker Compose vs Kubernetes\\"\\n4. **Recognize readiness** - When you stop needing tool suggestions, you're ready to build\\n\\n### The Fast Execution\\n\\nWhen the moment comes:\\n1. You already know the stack\\n2. AI handles integration details\\n3. You make architectural decisions in minutes (because you explored trade-offs months ago)\\n4. 10 hours of active work produces production-ready code\\n\\n**Why this is honest:** The 10 hours is real. But it's built on months of foundation.\\n\\n## The Sonnet 4.5 Catalyst\\n\\nWhy did this finally happen when Sonnet 4.5 released?\\n\\n**Better at synthesis:** Earlier models could explain tools. Sonnet 4.5 could integrate multiple tools I'd learned about separately.\\n\\n**Longer context:** It could reference patterns we'd discussed in earlier conversations, even if I didn't explicitly mention them.\\n\\n**Confidence:** I'd watched the models improve. When Sonnet 4.5 dropped, I knew it could handle the complexity I'd been accumulating knowledge for.\\n\\n**The moment:** Not \\"AI got good enough to build this.\\" But \\"I got ready, and the AI was ready too.\\"\\n\\n## What You Actually Learn\\n\\nThis process teaches:\\n\\n**Technical:**\\n- Why type safety matters at boundaries\\n- When Docker healthchecks prevent race conditions\\n- How content adapters enable flexibility\\n\\n**Strategic:**\\n- Recognizing tool fatigue (Express works, but do I need all of it?)\\n- Understanding trade-off spaces (VPS vs serverless vs homelab)\\n- Knowing when \\"good enough\\" beats \\"perfect\\"\\n\\n**Workflow:**\\n- Building mental toolkits over time\\n- Asking better questions as you learn\\n- Executing fast when foundation is solid\\n\\n## The Honest Timeline\\n\\n**Months 1-3:** Confused. Asking basic questions. Getting overwhelmed by options.\\n\\n**Months 4-6:** Patterns emerging. Starting to see why people choose certain tools.\\n\\n**Month 7:** Sonnet 4.5 releases. I realize I can name the stack I want.\\n\\n**Week 8:** 10 hours active work. Production site live.\\n\\n**The truth:** You can't skip to week 8. But you can accelerate months 1-7 by exploring deliberately.\\n\\n## How to Apply This\\n\\n### If You're Starting Now\\n\\n**Month 1:** Ask about fundamentals\\n- \\"Why use a framework vs vanilla JS?\\"\\n- \\"What problems do ORMs solve?\\"\\n- \\"When do I need Docker?\\"\\n\\nDon't build anything yet. Just understand the problem spaces.\\n\\n**Month 2:** Explore specific tools\\n- \\"I keep seeing Astro. What's it for?\\"\\n- \\"Why would I use Hono over Express?\\"\\n- \\"What's the deal with Directus?\\"\\n\\nFile away the answers. You might not use them for months.\\n\\n**Month 3:** Connect the dots\\n- \\"If I use Astro + Directus, how do they talk?\\"\\n- \\"What's the type safety story across that boundary?\\"\\n- \\"How does Docker fit into this?\\"\\n\\nNow you're thinking in systems.\\n\\n**Month 4:** You're ready\\n- You can describe what you want without asking for tool suggestions\\n- You ask \\"how do I integrate X and Y\\" not \\"what should I use\\"\\n- Execution is fast because decisions are already made\\n\\n### The Pattern\\n\\n**Explore → Connect → Recognize → Execute**\\n\\nThis portfolio represents: 6 months exploring, 1 moment recognizing, 10 hours executing.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Timeline:**\\n- 6 months learning with Claude Code\\n- 1 \\"I'm ready\\" moment when Sonnet 4.5 dropped\\n- 10 hours active implementation\\n\\n**Could you reproduce this?** Yes. But give yourself time to learn the pieces first.\\n\\n## The Real Insight\\n\\n**2023:** You needed to know the ecosystem before starting.\\n\\n**2025:** You can learn the ecosystem *through conversation*, accumulate knowledge gradually, then execute fast when ready.\\n\\n**The unlock:** AI as a patient teacher over months, then a fast collaborator when you're prepared.\\n\\nThe tools haven't changed. The learning curve has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Patient exploration → Gradual synthesis → Rapid execution when ready\\n","date_updated":"2025-10-14T06:41:33.771Z"}	\N	\N
155	182	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:50:48.649Z","title":"v0 to Production","published":true,"content":"One day of prompting for a production-ready portfolio. I knew exactly what to ask for.\\n\\n## The Setup\\n\\n**What I saw:** v0.dev templates at an AWS event locked to Vercel's framework.\\n\\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\\n\\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\\n\\n**Why it worked:** Curation and taste. Not because AI figured it out.\\n\\n## What AI Gives You Without Direction\\n\\nLeft to its own devices, Claude Code suggests:\\n\\n**The default stack:**\\n- Express (because it's popular)\\n- Basic JavaScript (because it's simple)\\n- Hardcoded data (because it works)\\n- Generic placeholders everywhere\\n\\n**What you get:** Something that runs. Nothing you'd ship.\\n\\nThis is the trap: AI coding tools *work*, but they optimize for \\"runs quickly\\" not \\"production-grade.\\"\\n\\n## What Changes with Curation\\n\\nWhen you know what exists, you can prompt differently.\\n\\n**Without curation:**\\n> \\"Build me a portfolio site\\"\\n\\nResult: Next.js with hardcoded content. Generic. Forgettable.\\n\\n**With curation:**\\n> \\"I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe.\\"\\n\\nResult: Production architecture in a day.\\n\\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\\n\\n## Where I Actually Learned\\n\\n### Tech Events\\n\\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: \\"Great UI, wrong stack for my needs.\\"\\n\\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\\n\\n### The Internet Annals\\n\\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\\n\\nNot tutorials. Real people discussing real trade-offs.\\n\\n### Small Experiments with Claude Code\\n\\nBuilding throwaway projects:\\n- \\"Show me how Directus works\\"\\n- \\"What's the Hono API surface look like?\\"\\n- \\"How does Astro handle dynamic routes?\\"\\n\\nRudimentary understanding. Just enough to know what's possible.\\n\\n## The Moment of Synthesis\\n\\nv0.dev templates are beautiful. But I wanted:\\n- Astro (better for content than Next.js)\\n- Self-hosted (not Vercel-locked)\\n- Directus (better admin UI than competitors)\\n- Hono (lighter than Express)\\n\\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\\n\\n## What One Day of Prompting Looks Like\\n\\n### Morning: The Conversion\\n\\n**Me:** \\"This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework.\\"\\n\\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\\n\\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\\n\\n### Afternoon: The Integration\\n\\n**Me:** \\"Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API.\\"\\n\\n**Claude Code:** Implements the adapter. Type-safe throughout.\\n\\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\\n\\n### Evening: The Deployment\\n\\n**Me:** \\"Docker Compose. Frontend, API, Directus. Healthchecks so they start in order.\\"\\n\\n**Claude Code:** Generates docker-compose.yml. We debug networking.\\n\\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\\n\\n## The LLM-Driven Issue Loop\\n\\nThis is where Sonnet 4.5 shines:\\n\\n**Pattern:**\\n1. Build a feature\\n2. Test it\\n3. Hit an error\\n4. Paste error to Claude Code\\n5. It suggests fix\\n6. Repeat\\n\\n**Example:**\\n- Docker services can't reach each other\\n- Paste error logs\\n- \\"Add them all to the same network\\"\\n- Works\\n\\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\\n\\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\\n\\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\\n\\n## What Curation Actually Means\\n\\n### 1. Knowing What Exists\\n\\nI can't ask for Hono if I don't know it exists. I learned it from:\\n- Tech event hallway conversation\\n- Seeing it on a \\"lightweight Node frameworks\\" list\\n- Building a throwaway API to understand it\\n\\n**The work:** Self-directed learning. Tech events. Experimentation.\\n\\n### 2. Understanding Trade-offs\\n\\nWhen Claude Code suggests Express, I know to push back: \\"What about Hono?\\"\\n\\nWhen it suggests Strapi, I counter with: \\"Directus has a better admin UI.\\"\\n\\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\\n\\n### 3. Recognizing Good Architecture\\n\\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\\n- Separates concerns\\n- Keeps Astro pages clean\\n- Makes CMS swappable\\n\\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\\n\\n### 4. Directing, Not Just Accepting\\n\\nDefault: \\"Build me X\\" → AI chooses everything\\n\\nCurated: \\"I want A, B, C integrated. Show me how\\" → You choose, AI implements\\n\\n**The difference:** Agency. You're in control.\\n\\n## Why This Moment Matters\\n\\n### The Timing\\n\\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\\n\\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\\n\\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\\n\\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\\n\\n### What Makes This Reproducible\\n\\nNot \\"use these exact tools.\\"\\n\\nBut: **Build your curation muscle, then execute with AI.**\\n\\n**How to build curation:**\\n1. Go to tech events (see tools demoed, hear hallway chatter)\\n2. Dig through forums (understand why people choose X over Y)\\n3. Build small experiments (gain rudimentary understanding)\\n4. Develop taste (know when \\"good enough\\" vs \\"production-grade\\")\\n\\n**Then when Sonnet 4.5 (or better) exists:**\\n- You can name what you want\\n- AI handles implementation details\\n- One day of focused work = production site\\n\\n## The Honest Comparison\\n\\n### Without Curation\\n**Prompt:** \\"Build me a portfolio site\\"\\n\\n**Result:** Express + basic JS + placeholders\\n\\n**Time to production:** Weeks of refactoring to make it real\\n\\n### With Curation\\n**Prompt:** \\"Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment.\\"\\n\\n**Result:** Production-grade architecture from day one\\n\\n**Time to production:** One day of focused prompting\\n\\n**The difference:** I did the learning beforehand. AI does the implementation now.\\n\\n## What You Actually Need to Learn\\n\\n**Not from AI:**\\n- What tools exist in the ecosystem\\n- Why people choose specific tools\\n- Trade-offs between options\\n- What \\"production-grade\\" looks like\\n\\n**From AI:**\\n- How to integrate specific tools\\n- Configuration syntax\\n- Implementation patterns\\n- Fixing specific errors\\n\\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\\n\\n## The Pattern\\n\\n**Phase 1: Self-Directed Learning**\\n- Attend tech events\\n- Read forums and GitHub issues\\n- Experiment with tools in isolation\\n- Develop opinions about trade-offs\\n\\n**Phase 2: Small Experiments**\\n- Build throwaway projects with Claude Code\\n- Gain rudimentary understanding\\n- Learn what's possible, what's hard\\n\\n**Phase 3: Recognition**\\n- \\"I know what I want to build\\"\\n- \\"I know which tools fit together\\"\\n- \\"I can direct an AI toward this vision\\"\\n\\n**Phase 4: Execution**\\n- One day of focused prompting\\n- LLM-driven issue loop (error → fix → repeat)\\n- Production-grade result\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Timeline:**\\n- Months of learning (events, experiments, forums)\\n- One day of building (prompting + iteration)\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\\n\\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\\n\\n## The Real Unlock\\n\\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\\n\\n**2025:** You need to know what to build and why. AI builds it for you.\\n\\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\\n\\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\\n\\n**When AI amplifies it:** When you can say \\"I want A, B, C integrated\\" and the AI handles implementation.\\n\\nThe tools haven't changed. The leverage has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\\n"}	{"content":"One day of prompting for a production-ready portfolio. I knew exactly what to ask for.\\n\\n## The Setup\\n\\n**What I saw:** v0.dev templates at an AWS event locked to Vercel's framework.\\n\\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\\n\\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\\n\\n**Why it worked:** Curation and taste. Not because AI figured it out.\\n\\n## What AI Gives You Without Direction\\n\\nLeft to its own devices, Claude Code suggests:\\n\\n**The default stack:**\\n- Express (because it's popular)\\n- Basic JavaScript (because it's simple)\\n- Hardcoded data (because it works)\\n- Generic placeholders everywhere\\n\\n**What you get:** Something that runs. Nothing you'd ship.\\n\\nThis is the trap: AI coding tools *work*, but they optimize for \\"runs quickly\\" not \\"production-grade.\\"\\n\\n## What Changes with Curation\\n\\nWhen you know what exists, you can prompt differently.\\n\\n**Without curation:**\\n> \\"Build me a portfolio site\\"\\n\\nResult: Next.js with hardcoded content. Generic. Forgettable.\\n\\n**With curation:**\\n> \\"I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe.\\"\\n\\nResult: Production architecture in a day.\\n\\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\\n\\n## Where I Actually Learned\\n\\n### Tech Events\\n\\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: \\"Great UI, wrong stack for my needs.\\"\\n\\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\\n\\n### The Internet Annals\\n\\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\\n\\nNot tutorials. Real people discussing real trade-offs.\\n\\n### Small Experiments with Claude Code\\n\\nBuilding throwaway projects:\\n- \\"Show me how Directus works\\"\\n- \\"What's the Hono API surface look like?\\"\\n- \\"How does Astro handle dynamic routes?\\"\\n\\nRudimentary understanding. Just enough to know what's possible.\\n\\n## The Moment of Synthesis\\n\\nv0.dev templates are beautiful. But I wanted:\\n- Astro (better for content than Next.js)\\n- Self-hosted (not Vercel-locked)\\n- Directus (better admin UI than competitors)\\n- Hono (lighter than Express)\\n\\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\\n\\n## What One Day of Prompting Looks Like\\n\\n### Morning: The Conversion\\n\\n**Me:** \\"This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework.\\"\\n\\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\\n\\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\\n\\n### Afternoon: The Integration\\n\\n**Me:** \\"Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API.\\"\\n\\n**Claude Code:** Implements the adapter. Type-safe throughout.\\n\\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\\n\\n### Evening: The Deployment\\n\\n**Me:** \\"Docker Compose. Frontend, API, Directus. Healthchecks so they start in order.\\"\\n\\n**Claude Code:** Generates docker-compose.yml. We debug networking.\\n\\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\\n\\n## The LLM-Driven Issue Loop\\n\\nThis is where Sonnet 4.5 shines:\\n\\n**Pattern:**\\n1. Build a feature\\n2. Test it\\n3. Hit an error\\n4. Paste error to Claude Code\\n5. It suggests fix\\n6. Repeat\\n\\n**Example:**\\n- Docker services can't reach each other\\n- Paste error logs\\n- \\"Add them all to the same network\\"\\n- Works\\n\\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\\n\\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\\n\\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\\n\\n## What Curation Actually Means\\n\\n### 1. Knowing What Exists\\n\\nI can't ask for Hono if I don't know it exists. I learned it from:\\n- Tech event hallway conversation\\n- Seeing it on a \\"lightweight Node frameworks\\" list\\n- Building a throwaway API to understand it\\n\\n**The work:** Self-directed learning. Tech events. Experimentation.\\n\\n### 2. Understanding Trade-offs\\n\\nWhen Claude Code suggests Express, I know to push back: \\"What about Hono?\\"\\n\\nWhen it suggests Strapi, I counter with: \\"Directus has a better admin UI.\\"\\n\\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\\n\\n### 3. Recognizing Good Architecture\\n\\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\\n- Separates concerns\\n- Keeps Astro pages clean\\n- Makes CMS swappable\\n\\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\\n\\n### 4. Directing, Not Just Accepting\\n\\nDefault: \\"Build me X\\" → AI chooses everything\\n\\nCurated: \\"I want A, B, C integrated. Show me how\\" → You choose, AI implements\\n\\n**The difference:** Agency. You're in control.\\n\\n## Why This Moment Matters\\n\\n### The Timing\\n\\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\\n\\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\\n\\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\\n\\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\\n\\n### What Makes This Reproducible\\n\\nNot \\"use these exact tools.\\"\\n\\nBut: **Build your curation muscle, then execute with AI.**\\n\\n**How to build curation:**\\n1. Go to tech events (see tools demoed, hear hallway chatter)\\n2. Dig through forums (understand why people choose X over Y)\\n3. Build small experiments (gain rudimentary understanding)\\n4. Develop taste (know when \\"good enough\\" vs \\"production-grade\\")\\n\\n**Then when Sonnet 4.5 (or better) exists:**\\n- You can name what you want\\n- AI handles implementation details\\n- One day of focused work = production site\\n\\n## The Honest Comparison\\n\\n### Without Curation\\n**Prompt:** \\"Build me a portfolio site\\"\\n\\n**Result:** Express + basic JS + placeholders\\n\\n**Time to production:** Weeks of refactoring to make it real\\n\\n### With Curation\\n**Prompt:** \\"Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment.\\"\\n\\n**Result:** Production-grade architecture from day one\\n\\n**Time to production:** One day of focused prompting\\n\\n**The difference:** I did the learning beforehand. AI does the implementation now.\\n\\n## What You Actually Need to Learn\\n\\n**Not from AI:**\\n- What tools exist in the ecosystem\\n- Why people choose specific tools\\n- Trade-offs between options\\n- What \\"production-grade\\" looks like\\n\\n**From AI:**\\n- How to integrate specific tools\\n- Configuration syntax\\n- Implementation patterns\\n- Fixing specific errors\\n\\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\\n\\n## The Pattern\\n\\n**Phase 1: Self-Directed Learning**\\n- Attend tech events\\n- Read forums and GitHub issues\\n- Experiment with tools in isolation\\n- Develop opinions about trade-offs\\n\\n**Phase 2: Small Experiments**\\n- Build throwaway projects with Claude Code\\n- Gain rudimentary understanding\\n- Learn what's possible, what's hard\\n\\n**Phase 3: Recognition**\\n- \\"I know what I want to build\\"\\n- \\"I know which tools fit together\\"\\n- \\"I can direct an AI toward this vision\\"\\n\\n**Phase 4: Execution**\\n- One day of focused prompting\\n- LLM-driven issue loop (error → fix → repeat)\\n- Production-grade result\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Timeline:**\\n- Months of learning (events, experiments, forums)\\n- One day of building (prompting + iteration)\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\\n\\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\\n\\n## The Real Unlock\\n\\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\\n\\n**2025:** You need to know what to build and why. AI builds it for you.\\n\\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\\n\\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\\n\\n**When AI amplifies it:** When you can say \\"I want A, B, C integrated\\" and the AI handles implementation.\\n\\nThe tools haven't changed. The leverage has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\\n","date_updated":"2025-10-14T06:50:48.649Z"}	\N	\N
120	132	work_projects	8	{"id":8,"status":"published","title":"Univar Solutions - Data Engineering","slug":"potion-data-engineering","company":"Potion (via Univar Solutions)","role":"Data Analyst","year":"2022","duration":"Contract","description":"Built data reconciliation pipeline for chemical formula database. Introduced Jupyter notebooks to annotation team, enabling large-scale cleanup effort.","content":"## Challenge\\n\\nChemical formulation database needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Built reconciliation system matching outdated names to original IDs\\n- Enabled bidirectional sync between golden dataset and production DB\\n- Automated cleanup and consolidation of redundant labels\\n\\n### Team Enablement\\n- Introduced Jupyter notebooks to annotation team\\n- Created tools for efficient data cleanup\\n- Trained team on data engineering best practices\\n\\n## Impact\\n- Saved hundreds of hours of manual work\\n- Made previously impossible database updates feasible\\n- Improved data quality for Univar Solutions chemical supply network\\n\\n## Technologies\\n- Data engineering and ETL\\n- Database reconciliation algorithms\\n- Jupyter for collaborative data work","technologies":["Python","Jupyter","Data Engineering","ETL","Database Systems"],"featured":true,"order":8,"team":null,"live_url":null,"case_study_url":null,"category":"employment"}	{"category":"employment"}	\N	\N
121	134	work_projects	2	{"id":2,"status":"published","title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Treasurer & Advisor","year":"2022-2024","duration":"2 years","description":"Served as treasurer and advisor for CS Club, supporting student leadership and helping organize 100+ tech events including hackathons, workshops, and hack nights.","content":"## Overview\\n\\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders in creating a thriving community that helped students succeed in tech careers.\\n\\n## Contributions\\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\\n- **Events**: Helped organize and advise 100+ tech events including hackathons, workshops, hack nights, and meetups\\n- **Education**: Introduced students to modern web frameworks like Astro, helping them build professional portfolios\\n- **Community Site**: Built https://ccsf-cs.club for resources and announcements\\n- **Mentorship**: Provided guidance while empowering younger students to take leadership roles\\n\\n## Impact\\n- Mentored first-time hackathon participants\\n- Connected students with SF tech community\\n- Created pathways for non-traditional students into tech careers\\n- Supported student-led initiatives by managing finances and providing technical expertise","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":2,"team":null,"live_url":"https://ccsf-cs.club","case_study_url":null,"category":"education"}	{"role":"Treasurer & Advisor","description":"Served as treasurer and advisor for CS Club, supporting student leadership and helping organize 100+ tech events including hackathons, workshops, and hack nights.","content":"## Overview\\n\\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders in creating a thriving community that helped students succeed in tech careers.\\n\\n## Contributions\\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\\n- **Events**: Helped organize and advise 100+ tech events including hackathons, workshops, hack nights, and meetups\\n- **Education**: Introduced students to modern web frameworks like Astro, helping them build professional portfolios\\n- **Community Site**: Built https://ccsf-cs.club for resources and announcements\\n- **Mentorship**: Provided guidance while empowering younger students to take leadership roles\\n\\n## Impact\\n- Mentored first-time hackathon participants\\n- Connected students with SF tech community\\n- Created pathways for non-traditional students into tech careers\\n- Supported student-led initiatives by managing finances and providing technical expertise"}	\N	\N
122	135	work_projects	3	{"id":3,"status":"published","title":"Tech Event Analyzer - Hackathon Project","slug":"tech-event-analyzer","company":"Hackathon Project","role":"Full Stack Developer","year":"2024","duration":"4 hours","description":"Discovered undocumented Lu.ma pagination API and built analyzer to identify which tech companies consistently provide food at events. Found Cloudflare, AWS, and GitHub as top sponsors.","content":"## Problem\\n\\nTech event attendees need to know which events are worth attending beyond just the topic.\\n\\n## Solution\\n\\nBuilt a scraper and analyzer that:\\n- Discovered and utilized undocumented Lu.ma pagination API endpoint\\n- Extracted event data including sponsors and amenities\\n- Identified patterns in sponsor behavior\\n- Ranked companies by event quality metrics\\n\\n## Key Findings\\n- Cloudflare, AWS, and GitHub consistently budget for attendee food\\n- Correlation between food quality and event engagement\\n- Useful for event planning and attendee decision-making\\n\\n## Technologies\\n- API reverse engineering\\n- Data analysis and visualization\\n- Pattern recognition","technologies":["Python","API Scraping","Data Analysis","Lu.ma"],"featured":true,"order":3,"team":null,"live_url":null,"case_study_url":null,"category":"hackathon"}	{"description":"Discovered undocumented Lu.ma pagination API and built analyzer to identify which tech companies consistently provide food at events. Found Cloudflare, AWS, and GitHub as top sponsors.","content":"## Problem\\n\\nTech event attendees need to know which events are worth attending beyond just the topic.\\n\\n## Solution\\n\\nBuilt a scraper and analyzer that:\\n- Discovered and utilized undocumented Lu.ma pagination API endpoint\\n- Extracted event data including sponsors and amenities\\n- Identified patterns in sponsor behavior\\n- Ranked companies by event quality metrics\\n\\n## Key Findings\\n- Cloudflare, AWS, and GitHub consistently budget for attendee food\\n- Correlation between food quality and event engagement\\n- Useful for event planning and attendee decision-making\\n\\n## Technologies\\n- API reverse engineering\\n- Data analysis and visualization\\n- Pattern recognition"}	\N	\N
123	136	work_projects	5	{"id":5,"status":"published","title":"Piper - STEM Learning Platform","slug":"piper","company":"Piper, Inc.","role":"Software Engineer","year":"2018-2021","duration":"3 years 5 months","description":"Full-stack engineer on STEM learning platform combining hardware and software. Key contributor to expansion pack release, PiperStory (Minecraft-based game mode), and PiperCode (Blockly/Scratch teaching tool).","content":"## Role & Responsibilities\\n\\nFull-stack engineer on Python-based STEM learning platform for K-12 education, combining Raspberry Pi hardware with custom software.\\n\\n## Key Projects\\n\\n### PiperStory Game Mode\\n- Raspberry Pi-based modded Minecraft system\\n- Built on top of Minecraft Pi Edition\\n- Created educational game experiences for kids learning electronics and programming\\n\\n### PiperCode Teaching Tool\\n- React-based Electron app using Blockly/Scratch\\n- Visual programming interface for kids to learn coding concepts\\n- Integrated with hardware projects\\n\\n### Expansion Pack (DLC)\\n- Key contributor to major content release as part of core dev team\\n- Improved customer engagement and retention\\n- Extended platform capabilities with new features\\n\\n### Infrastructure & Analytics\\n- **Analytics Dashboard**: Set up SQL and Amplitude for marketing, QA, and dev-ops intelligence\\n- **Survey System**: Developed FERPA-compliant web service using JavaScript, Google Apps Engine, and Firebase\\n- **Technical Blog**: Created content exploring CS and EE concepts through DIY projects\\n\\n## Impact\\n- Part of small team delivering STEM education to K-12 students nationwide\\n- Contributed to product development across hardware/software integration\\n- Built tools that made learning electronics and programming accessible to kids\\n\\n*Note: Piper is no longer in production as of 2021*","technologies":["Python","JavaScript","SQL","Firebase","Google Apps Engine","Amplitude","Game Development"],"featured":true,"order":5,"team":null,"live_url":null,"case_study_url":null,"category":"employment"}	{"description":"Full-stack engineer on STEM learning platform combining hardware and software. Key contributor to expansion pack release, PiperStory (Minecraft-based game mode), and PiperCode (Blockly/Scratch teaching tool).","content":"## Role & Responsibilities\\n\\nFull-stack engineer on Python-based STEM learning platform for K-12 education, combining Raspberry Pi hardware with custom software.\\n\\n## Key Projects\\n\\n### PiperStory Game Mode\\n- Raspberry Pi-based modded Minecraft system\\n- Built on top of Minecraft Pi Edition\\n- Created educational game experiences for kids learning electronics and programming\\n\\n### PiperCode Teaching Tool\\n- React-based Electron app using Blockly/Scratch\\n- Visual programming interface for kids to learn coding concepts\\n- Integrated with hardware projects\\n\\n### Expansion Pack (DLC)\\n- Key contributor to major content release as part of core dev team\\n- Improved customer engagement and retention\\n- Extended platform capabilities with new features\\n\\n### Infrastructure & Analytics\\n- **Analytics Dashboard**: Set up SQL and Amplitude for marketing, QA, and dev-ops intelligence\\n- **Survey System**: Developed FERPA-compliant web service using JavaScript, Google Apps Engine, and Firebase\\n- **Technical Blog**: Created content exploring CS and EE concepts through DIY projects\\n\\n## Impact\\n- Part of small team delivering STEM education to K-12 students nationwide\\n- Contributed to product development across hardware/software integration\\n- Built tools that made learning electronics and programming accessible to kids\\n\\n*Note: Piper is no longer in production as of 2021*"}	\N	\N
124	138	work_projects	1	{"id":1,"status":"published","title":"My Little Soda - Autonomous Coding Agent","slug":"my-little-soda","company":"Open Source","role":"Creator & Maintainer","year":"2025","duration":"Ongoing","description":"GitHub Issues-driven autonomous coding tool that uses LLMs to automatically implement features and fix bugs.","content":"## Overview\\n\\nBuilt an autonomous coding agent that monitors GitHub Issues and automatically generates pull requests with working code implementations.\\n\\n## Technical Implementation\\n- Integrates with GitHub API for issue tracking\\n- Uses Claude/GPT for code generation\\n- Implements automated testing and validation\\n- Handles PR creation and code review workflows\\n\\n## Impact\\n- Demonstrates practical agent architecture patterns\\n- Reduces time from issue creation to implementation\\n- Open source tool for developer productivity","technologies":["Python","GitHub API","Claude","GPT","Autonomous Agents"],"featured":true,"order":1,"team":null,"live_url":"https://github.com/johnhkchen/my-little-soda","case_study_url":null,"category":"open-source"}	{"year":"2025"}	\N	\N
125	139	work_projects	2	{"id":2,"status":"published","title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Treasurer & Advisor","year":"2023-present","duration":"2 years+","description":"Served as treasurer and advisor for CS Club, supporting student leadership and helping organize 100+ tech events including hackathons, workshops, and hack nights.","content":"## Overview\\n\\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders in creating a thriving community that helped students succeed in tech careers.\\n\\n## Contributions\\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\\n- **Events**: Helped organize and advise 100+ tech events including hackathons, workshops, hack nights, and meetups\\n- **Education**: Introduced students to modern web frameworks like Astro, helping them build professional portfolios\\n- **Community Site**: Built https://ccsf-cs.club for resources and announcements\\n- **Mentorship**: Provided guidance while empowering younger students to take leadership roles\\n\\n## Impact\\n- Mentored first-time hackathon participants\\n- Connected students with SF tech community\\n- Created pathways for non-traditional students into tech careers\\n- Supported student-led initiatives by managing finances and providing technical expertise","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":2,"team":null,"live_url":"https://ccsf-cs.club","case_study_url":null,"category":"education"}	{"year":"2023-present","duration":"2 years+"}	\N	\N
142	163	skills	2	{"id":2,"name":"ChatGPT","category":"aiml","proficiency":"expert","order":2,"featured":true}	{"name":"ChatGPT"}	\N	\N
151	177	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:41:43.714Z","title":"v0 to Production","published":true,"content":"# Building Production Sites with AI: How Accumulated Knowledge Becomes Execution\\n\\nThis isn't a \\"10 hours from zero to production\\" story. This is about learning gradually, recognizing when you're ready, and executing fast because you built the foundation.\\n\\n## The Real Timeline\\n\\n**Months before:** Experimenting with Claude Code. Asking about containers. Trying to understand web frameworks. Getting suggestions for tools I didn't have time to integrate yet.\\n\\n**The moment:** Sonnet 4.5 releases. I realize: I'm ready. All those scattered learnings can finally come together.\\n\\n**The execution:** 10 hours of active work to build the portfolio. Not because AI is magic, but because I'd been learning the pieces for months.\\n\\n## How Learning Accumulates\\n\\n### Phase 1: Curiosity Without Application\\n\\nEarly conversations with Claude Code:\\n\\n**Me:** \\"What's the difference between Docker Compose and Kubernetes?\\"\\n\\n**Claude Code:** Explains orchestration, when you need each, complexity trade-offs.\\n\\nI file this away. Don't use it immediately. But now I know Docker Compose exists.\\n\\n---\\n\\n**Me:** \\"Why would I use a headless CMS instead of just markdown files?\\"\\n\\n**Claude Code:** Explains non-technical editors, API flexibility, content reuse.\\n\\nAnother piece filed away. Maybe useful later.\\n\\n---\\n\\n**Me:** \\"What makes TypeScript worth the setup overhead?\\"\\n\\n**Claude Code:** Type safety at boundaries, catching errors at build time, better tooling.\\n\\nI start to see patterns forming.\\n\\n### Phase 2: Connecting the Dots\\n\\nMonths later, different conversation:\\n\\n**Me:** \\"I keep seeing Astro mentioned. What's the point if I already know React?\\"\\n\\n**Claude Code:** Content-first architecture, zero JavaScript by default, better for portfolios than full SPAs.\\n\\nThis connects to the \\"static vs dynamic\\" conversation from two months ago.\\n\\n---\\n\\n**Me:** \\"Everyone uses Express for Node APIs. Is there a reason to use anything else?\\"\\n\\n**Claude Code:** For lightweight APIs, Hono is 12KB vs 200KB. Edge-ready, better TypeScript DX.\\n\\nI remember the \\"keep it simple\\" advice from earlier. This fits.\\n\\n### Phase 3: The Synthesis Moment\\n\\nSonnet 4.5 drops. I decide: time to build the portfolio.\\n\\nNow, instead of asking \\"How do I build a portfolio?\\", I can ask:\\n\\n> \\"I have an Astro site from v0.dev. I want Directus for content, a lightweight API layer, type safety across the stack, and Docker deployment. Based on what we've discussed before, what's the integration approach?\\"\\n\\nClaude Code doesn't need to convince me of the tools. We've already explored them. It jumps straight to implementation.\\n\\n**This is the unlock:** Accumulated context lets you move fast.\\n\\n## What This Actually Looks Like\\n\\n### Without Foundation (How I Started)\\n\\n**Me:** \\"Build me a portfolio site\\"\\n\\n**Claude Code:** \\"Here's a Next.js app with...\\"\\n\\n**Me:** \\"Why Next.js?\\"\\n\\n**Claude Code:** Explains SSR, routing, ecosystem...\\n\\n**Me:** \\"What's SSR?\\"\\n\\nI'm learning fundamentals while trying to build. Slow.\\n\\n### With Foundation (How It Ended)\\n\\n**Me:** \\"Astro frontend, Directus CMS, Hono API. Show me the content adapter pattern.\\"\\n\\n**Claude Code:** *Shows implementation*\\n\\n**Me:** \\"Type safety chain across all three?\\"\\n\\n**Claude Code:** *Shows TypeScript interfaces*\\n\\nI already understand SSR, why Astro, why Directus, what an API layer does. We're discussing implementation, not fundamentals.\\n\\n## The Methodology That Emerged\\n\\nOver months of exploration, these patterns became clear:\\n\\n### 1. Ask About Trade-offs, Not Just \\"How\\"\\n\\nEarly on, I'd ask: \\"How do I deploy this?\\"\\n\\nNow I ask: \\"I'm choosing between nginx reverse proxy and Cloudflare Tunnels. What am I trading off?\\"\\n\\nThe shift: From \\"teach me to do it\\" to \\"help me decide.\\"\\n\\n### 2. Explore Before You Need\\n\\nI asked about Directus six months before building this site. When the moment came, I knew it was the right tool.\\n\\n**The pattern:** Curiosity-driven learning builds a mental toolkit. When you need something, you already know it exists.\\n\\n### 3. Recognize When You're Ready\\n\\nThe signal: You stop asking \\"What should I use?\\" and start asking \\"How do I integrate these specific things?\\"\\n\\nFor me, that moment was realizing I could name the stack I wanted without Claude Code suggesting it.\\n\\n### 4. Execute Fast on Familiar Ground\\n\\nWith the foundation built, implementation is fast:\\n- I know why Docker Compose over Kubernetes\\n- I know why Hono over Express\\n- I know why Directus over Strapi\\n- I know what type safety buys me\\n\\nClaude Code handles syntax and configuration. I handle architecture.\\n\\n## What Makes This Reproducible\\n\\n### The Patient Approach\\n\\n1. **Explore without deadline** - Ask about tools when you see them mentioned, even if you don't need them yet\\n2. **Connect conversations** - \\"You mentioned X last month. How does that relate to Y?\\"\\n3. **Build mental models** - Not just \\"how to use Docker\\" but \\"when Docker Compose vs Kubernetes\\"\\n4. **Recognize readiness** - When you stop needing tool suggestions, you're ready to build\\n\\n### The Fast Execution\\n\\nWhen the moment comes:\\n1. You already know the stack\\n2. AI handles integration details\\n3. You make architectural decisions in minutes (because you explored trade-offs months ago)\\n4. 10 hours of active work produces production-ready code\\n\\n**Why this is honest:** The 10 hours is real. But it's built on months of foundation.\\n\\n## The Sonnet 4.5 Catalyst\\n\\nWhy did this finally happen when Sonnet 4.5 released?\\n\\n**Better at synthesis:** Earlier models could explain tools. Sonnet 4.5 could integrate multiple tools I'd learned about separately.\\n\\n**Longer context:** It could reference patterns we'd discussed in earlier conversations, even if I didn't explicitly mention them.\\n\\n**Confidence:** I'd watched the models improve. When Sonnet 4.5 dropped, I knew it could handle the complexity I'd been accumulating knowledge for.\\n\\n**The moment:** Not \\"AI got good enough to build this.\\" But \\"I got ready, and the AI was ready too.\\"\\n\\n## What You Actually Learn\\n\\nThis process teaches:\\n\\n**Technical:**\\n- Why type safety matters at boundaries\\n- When Docker healthchecks prevent race conditions\\n- How content adapters enable flexibility\\n\\n**Strategic:**\\n- Recognizing tool fatigue (Express works, but do I need all of it?)\\n- Understanding trade-off spaces (VPS vs serverless vs homelab)\\n- Knowing when \\"good enough\\" beats \\"perfect\\"\\n\\n**Workflow:**\\n- Building mental toolkits over time\\n- Asking better questions as you learn\\n- Executing fast when foundation is solid\\n\\n## The Honest Timeline\\n\\n**Months 1-3:** Confused. Asking basic questions. Getting overwhelmed by options.\\n\\n**Months 4-6:** Patterns emerging. Starting to see why people choose certain tools.\\n\\n**Month 7:** Sonnet 4.5 releases. I realize I can name the stack I want.\\n\\n**Week 8:** 10 hours active work. Production site live.\\n\\n**The truth:** You can't skip to week 8. But you can accelerate months 1-7 by exploring deliberately.\\n\\n## How to Apply This\\n\\n### If You're Starting Now\\n\\n**Month 1:** Ask about fundamentals\\n- \\"Why use a framework vs vanilla JS?\\"\\n- \\"What problems do ORMs solve?\\"\\n- \\"When do I need Docker?\\"\\n\\nDon't build anything yet. Just understand the problem spaces.\\n\\n**Month 2:** Explore specific tools\\n- \\"I keep seeing Astro. What's it for?\\"\\n- \\"Why would I use Hono over Express?\\"\\n- \\"What's the deal with Directus?\\"\\n\\nFile away the answers. You might not use them for months.\\n\\n**Month 3:** Connect the dots\\n- \\"If I use Astro + Directus, how do they talk?\\"\\n- \\"What's the type safety story across that boundary?\\"\\n- \\"How does Docker fit into this?\\"\\n\\nNow you're thinking in systems.\\n\\n**Month 4:** You're ready\\n- You can describe what you want without asking for tool suggestions\\n- You ask \\"how do I integrate X and Y\\" not \\"what should I use\\"\\n- Execution is fast because decisions are already made\\n\\n### The Pattern\\n\\n**Explore → Connect → Recognize → Execute**\\n\\nThis portfolio represents: 6 months exploring, 1 moment recognizing, 10 hours executing.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Timeline:**\\n- 6 months learning with Claude Code\\n- 1 \\"I'm ready\\" moment when Sonnet 4.5 dropped\\n- 10 hours active implementation\\n\\n**Could you reproduce this?** Yes. But give yourself time to learn the pieces first.\\n\\n## The Real Insight\\n\\n**2023:** You needed to know the ecosystem before starting.\\n\\n**2025:** You can learn the ecosystem *through conversation*, accumulate knowledge gradually, then execute fast when ready.\\n\\n**The unlock:** AI as a patient teacher over months, then a fast collaborator when you're prepared.\\n\\nThe tools haven't changed. The learning curve has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Patient exploration → Gradual synthesis → Rapid execution when ready\\n"}	{"title":"v0 to Production","date_updated":"2025-10-14T06:41:43.714Z"}	\N	\N
157	188	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T06:59:36.595Z","title":"Building My Portfolio with Claude Code","published":true,"content":"# The Velocity Shift: Building My Portfolio with Claude Code in 2025\\n\\nTen hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (I knew content-first > full SPA)\\n- Directus over Strapi (better admin UI, saw it demoed)\\n- Hono over Express (lighter, saw it mentioned at a meetup)\\n- Docker Compose over Kubernetes (right scale for homelab)\\n- Cloudflare Tunnels over nginx (simpler, more secure)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n"}	{"title":"Building My Portfolio with Claude Code","date_updated":"2025-10-14T06:59:36.595Z"}	\N	\N
158	189	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T06:59:52.571Z","title":"Building My Portfolio with Claude Code","published":true,"content":"Ten hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (I knew content-first > full SPA)\\n- Directus over Strapi (better admin UI, saw it demoed)\\n- Hono over Express (lighter, saw it mentioned at a meetup)\\n- Docker Compose over Kubernetes (right scale for homelab)\\n- Cloudflare Tunnels over nginx (simpler, more secure)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n"}	{"content":"Ten hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (I knew content-first > full SPA)\\n- Directus over Strapi (better admin UI, saw it demoed)\\n- Hono over Express (lighter, saw it mentioned at a meetup)\\n- Docker Compose over Kubernetes (right scale for homelab)\\n- Cloudflare Tunnels over nginx (simpler, more secure)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n","date_updated":"2025-10-14T06:59:52.571Z"}	\N	\N
126	140	work_projects	4	{"id":4,"status":"published","title":"SF Legacy Business Registry - Civic Tech","slug":"sf-legacy-business-registry","company":"Hackathon Project","role":"Full Stack Developer","year":"2025","duration":"8 hours","description":"Built PDF-to-structured-data pipeline using LlamaParse to transform San Francisco legacy business applications into an engaging, searchable database.","content":"## Problem\\n\\nSan Francisco's legacy business data was trapped in PDF application forms, making it difficult to discover and explore the city's historic businesses.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Used LlamaParse to extract structured data from PDF applications\\n- Cleaned and normalized business information\\n- Built searchable database with rich metadata\\n\\n### User Experience\\n- Created engaging visual interface for browsing businesses\\n- Added filtering by neighborhood, business type, and year established\\n- Implemented search functionality\\n\\n## Impact\\n- Made civic data accessible and useful\\n- Demonstrated practical LLM applications for document processing\\n- Created reusable pipeline for similar civic tech projects\\n\\n## Tech Stack\\n- LlamaParse for PDF extraction\\n- Vector search for semantic queries\\n- Modern web framework for UI","technologies":["LlamaParse","PDF Processing","Civic Tech","Vector Search","Full Stack"],"featured":true,"order":4,"team":null,"live_url":null,"case_study_url":null,"category":"hackathon"}	{"year":"2025"}	\N	\N
127	141	work_projects	8	{"id":8,"status":"published","title":"Univar Solutions - Data Engineering","slug":"potion-data-engineering","company":"Potion","role":"Data Analyst (Contract)","year":"2022","duration":"Contract","description":"Contract data analyst for Potion, a software consultancy serving Univar Solutions. Built data reconciliation pipeline for chemical formula database and introduced Jupyter notebooks to annotation team.","content":"## Challenge\\n\\nChemical formulation database at Univar Solutions needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Built reconciliation system matching outdated names to original IDs\\n- Enabled bidirectional sync between golden dataset and production DB\\n- Automated cleanup and consolidation of redundant labels\\n\\n### Team Enablement\\n- Introduced Jupyter notebooks to annotation team\\n- Created tools for efficient data cleanup\\n- Trained team on data engineering best practices\\n\\n## Impact\\n- Saved hundreds of hours of manual work\\n- Made previously impossible database updates feasible\\n- Improved data quality for Univar Solutions chemical supply network\\n\\n## Technologies\\n- Data engineering and ETL\\n- Database reconciliation algorithms\\n- Jupyter for collaborative data work\\n\\n*Contract role through Potion, providing services to Univar Solutions*","technologies":["Python","Jupyter","Data Engineering","ETL","Database Systems"],"featured":true,"order":8,"team":null,"live_url":null,"case_study_url":null,"category":"employment"}	{"company":"Potion","role":"Data Analyst (Contract)","description":"Contract data analyst for Potion, a software consultancy serving Univar Solutions. Built data reconciliation pipeline for chemical formula database and introduced Jupyter notebooks to annotation team.","content":"## Challenge\\n\\nChemical formulation database at Univar Solutions needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Built reconciliation system matching outdated names to original IDs\\n- Enabled bidirectional sync between golden dataset and production DB\\n- Automated cleanup and consolidation of redundant labels\\n\\n### Team Enablement\\n- Introduced Jupyter notebooks to annotation team\\n- Created tools for efficient data cleanup\\n- Trained team on data engineering best practices\\n\\n## Impact\\n- Saved hundreds of hours of manual work\\n- Made previously impossible database updates feasible\\n- Improved data quality for Univar Solutions chemical supply network\\n\\n## Technologies\\n- Data engineering and ETL\\n- Database reconciliation algorithms\\n- Jupyter for collaborative data work\\n\\n*Contract role through Potion, providing services to Univar Solutions*"}	\N	\N
128	143	work_projects	2	{"id":2,"status":"published","title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Treasurer & Advisor","year":"2023-present","duration":"2 years+","description":"Treasurer and advisor for CS Club. Built https://ccsf-cs.club using Astro, achieving #1 Google ranking for CS clubs in SF. Led student teams attending tech events across the Bay Area.","content":"## Overview\\n\\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders while contributing technical expertise and event coordination.\\n\\n## Key Contributions\\n\\n### Website & Online Presence\\n- Built https://ccsf-cs.club using Astro framework\\n- Achieved #1 Google ranking for \\"CS club\\" searches in San Francisco region\\n- Created resource hub for students learning modern web development\\n- Introduced students to Astro, helping them build professional portfolios\\n\\n### Event Leadership\\n- Led student teams attending 100+ tech events across the Bay Area\\n- Organized group attendance at hackathons, workshops, and tech meetups\\n- Connected students with SF tech community opportunities\\n- Mentored first-time hackathon participants\\n\\n### Administrative Support\\n- Managed club finances as treasurer\\n- Provided guidance while empowering younger students to take leadership roles\\n- Supported student-led initiatives with financial and technical expertise\\n\\n## Impact\\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\\n- **Community Growth**: Helped build thriving community connecting CCSF students to tech careers\\n- **Technical Education**: Created pathways for non-traditional students into tech through accessible resources and mentorship\\n\\n*2023-present*","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":2,"team":null,"live_url":"https://ccsf-cs.club","case_study_url":null,"category":"education"}	{"description":"Treasurer and advisor for CS Club. Built https://ccsf-cs.club using Astro, achieving #1 Google ranking for CS clubs in SF. Led student teams attending tech events across the Bay Area.","content":"## Overview\\n\\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders while contributing technical expertise and event coordination.\\n\\n## Key Contributions\\n\\n### Website & Online Presence\\n- Built https://ccsf-cs.club using Astro framework\\n- Achieved #1 Google ranking for \\"CS club\\" searches in San Francisco region\\n- Created resource hub for students learning modern web development\\n- Introduced students to Astro, helping them build professional portfolios\\n\\n### Event Leadership\\n- Led student teams attending 100+ tech events across the Bay Area\\n- Organized group attendance at hackathons, workshops, and tech meetups\\n- Connected students with SF tech community opportunities\\n- Mentored first-time hackathon participants\\n\\n### Administrative Support\\n- Managed club finances as treasurer\\n- Provided guidance while empowering younger students to take leadership roles\\n- Supported student-led initiatives with financial and technical expertise\\n\\n## Impact\\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\\n- **Community Growth**: Helped build thriving community connecting CCSF students to tech careers\\n- **Technical Education**: Created pathways for non-traditional students into tech through accessible resources and mentorship\\n\\n*2023-present*"}	\N	\N
129	145	work_projects	6	{"id":6,"status":"published","title":"IdeaWall - HCI Research","slug":"ideawall-research","company":"UC Davis Visualization Lab","role":"Research Assistant","year":"2015-2016","duration":"1 year 2 months","description":"Research assistant on ACM CSCW paper about AI-augmented creative collaboration. Contributed to user studies, Mandarin-to-English copyediting, and publication process for IdeaWall system.","content":"## Research Project\\n\\n**Published**: ACM Conference on Computer Supported Cooperative Work and Social Computing (CSCW '17)\\n\\n## Overview\\n\\nResearch assistant at UC Davis Visualization Lab working on IdeaWall, an intelligent system that augments verbal creative collaboration with real-time visual stimuli.\\n\\n## Contributions\\n\\n### User Studies\\n- Conducted and facilitated user testing sessions\\n- Helped coordinate study with 24 participants across 12 groups\\n- Collected and documented research data\\n\\n### Publication Support\\n- Mandarin-to-English copyediting for international collaboration\\n- Assisted with paper revision and submission process\\n- Contributed to getting paper accepted at competitive HCI venue\\n\\n### Technical Support\\n- Assisted with real-time speech processing and information extraction system\\n- Supported web search integration for contextual materials\\n- Helped develop visual display system with three cognitive strategies\\n\\n## Research Impact\\n- Junior author on paper demonstrating effectiveness of AI-assisted collaboration tools\\n- Contributed to validating three cognitive strategies for visual facilitation\\n- Helped establish foundation for future intelligent groupware systems\\n\\n## Skills Developed\\n- Research methodology and user testing\\n- Academic writing and publication process\\n- Cross-cultural collaboration and translation\\n- Human-computer interaction design","technologies":["HCI Research","Real-time Processing","User Studies","Data Visualization","Academic Writing"],"featured":true,"order":6,"team":null,"live_url":null,"case_study_url":"http://dl.acm.org/citation.cfm?id=2998208","category":"research"}	{"description":"Research assistant on ACM CSCW paper about AI-augmented creative collaboration. Contributed to user studies, Mandarin-to-English copyediting, and publication process for IdeaWall system.","content":"## Research Project\\n\\n**Published**: ACM Conference on Computer Supported Cooperative Work and Social Computing (CSCW '17)\\n\\n## Overview\\n\\nResearch assistant at UC Davis Visualization Lab working on IdeaWall, an intelligent system that augments verbal creative collaboration with real-time visual stimuli.\\n\\n## Contributions\\n\\n### User Studies\\n- Conducted and facilitated user testing sessions\\n- Helped coordinate study with 24 participants across 12 groups\\n- Collected and documented research data\\n\\n### Publication Support\\n- Mandarin-to-English copyediting for international collaboration\\n- Assisted with paper revision and submission process\\n- Contributed to getting paper accepted at competitive HCI venue\\n\\n### Technical Support\\n- Assisted with real-time speech processing and information extraction system\\n- Supported web search integration for contextual materials\\n- Helped develop visual display system with three cognitive strategies\\n\\n## Research Impact\\n- Junior author on paper demonstrating effectiveness of AI-assisted collaboration tools\\n- Contributed to validating three cognitive strategies for visual facilitation\\n- Helped establish foundation for future intelligent groupware systems\\n\\n## Skills Developed\\n- Research methodology and user testing\\n- Academic writing and publication process\\n- Cross-cultural collaboration and translation\\n- Human-computer interaction design"}	\N	\N
130	147	work_projects	2	{"id":2,"status":"published","title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Treasurer & Advisor","year":"2023-present","duration":"2 years+","description":"Treasurer and advisor for CS Club. Built https://ccsf-cs.club using Astro, achieving #1 Google ranking for CS clubs in SF. Led student teams attending tech events across the Bay Area.","content":"## Overview\\n\\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders while contributing technical expertise and event coordination.\\n\\n## Key Contributions\\n\\n### Website & Online Presence\\n- Built https://ccsf-cs.club using Astro framework\\n- Achieved #1 Google ranking for \\"CS club\\" searches in San Francisco region\\n- Created resource hub for students learning modern web development\\n- Introduced students to Astro, helping them build professional portfolios\\n\\n### Event Leadership\\n- Led student teams attending 100+ tech events across the Bay Area\\n- Organized group attendance at hackathons, workshops, and tech meetups\\n- Connected students with SF tech community opportunities\\n- Mentored first-time hackathon participants\\n\\n### Administrative Support\\n- Managed club finances as treasurer\\n- Provided guidance while empowering younger students to take leadership roles\\n- Supported student-led initiatives with financial and technical expertise\\n\\n## Impact\\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\\n- **Community Growth**: Helped build thriving community connecting CCSF students to tech careers\\n- **Technical Education**: Created pathways for non-traditional students into tech through accessible resources and mentorship\\n\\n*2023-present*","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":1,"team":null,"live_url":"https://ccsf-cs.club","case_study_url":null,"category":"education"}	{"order":1}	\N	\N
144	165	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T06:03:09.529Z","title":"Building My Portfolio with Claude Code in 2025","published":true,"content":"Convert v0 v0.dev templates and deploy to a home server. It takes hours, not weeks.\\n\\n## Why 2025 is Different\\n\\nThis project would have taken a month in 2023. In 2025, with Claude Code, it took days. The fundamentals haven't changed—JAMstack is still JAMstack—but the tooling finally works.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, built for Vercel with hardcoded content.\\n\\n**The goal:** Self-host it with a CMS. No code changes for updates.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nInstead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces, I described what I wanted. Claude Code handled:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup\\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code:\\n- Added category system to distinguish employment vs hackathons vs research\\n- Fixed chronological ordering in work history\\n- Corrected exaggerated claims and dates\\n- Updated descriptions for accuracy\\n- Implemented minimalist social link design\\n- Added template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n\\n✅ **Cost** - One-time hardware, no monthly fees\\n\\n✅ **Learning** - Understand every layer of the stack\\n\\n✅ **Privacy** - My data stays on my hardware\\n\\n✅ **Flexibility** - Can run whatever services I want\\n\\n\\nCloudflare Tunnels solved the hard part: HTTPS, no port forwarding, DDoS protection.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration\\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I corrected exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"\\n# Claude Code: Rewrites to emphasize supporting student leaders while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about replacement—it's about removing friction. I make every decision. Claude Code eliminates boilerplate, configuration, and TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours\\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved days of design work\\n2. **LLMs excel at structure, watch accuracy** - Fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack delivers** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy\\n- Add analytics (privacy-friendly)\\n\\nThe key win? **I can do all of that in Directus, without touching code.**\\n\\n\\n"}	{"content":"Convert v0 v0.dev templates and deploy to a home server. It takes hours, not weeks.\\n\\n## Why 2025 is Different\\n\\nThis project would have taken a month in 2023. In 2025, with Claude Code, it took days. The fundamentals haven't changed—JAMstack is still JAMstack—but the tooling finally works.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, built for Vercel with hardcoded content.\\n\\n**The goal:** Self-host it with a CMS. No code changes for updates.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nInstead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces, I described what I wanted. Claude Code handled:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup\\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code:\\n- Added category system to distinguish employment vs hackathons vs research\\n- Fixed chronological ordering in work history\\n- Corrected exaggerated claims and dates\\n- Updated descriptions for accuracy\\n- Implemented minimalist social link design\\n- Added template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n\\n✅ **Cost** - One-time hardware, no monthly fees\\n\\n✅ **Learning** - Understand every layer of the stack\\n\\n✅ **Privacy** - My data stays on my hardware\\n\\n✅ **Flexibility** - Can run whatever services I want\\n\\n\\nCloudflare Tunnels solved the hard part: HTTPS, no port forwarding, DDoS protection.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration\\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I corrected exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"\\n# Claude Code: Rewrites to emphasize supporting student leaders while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about replacement—it's about removing friction. I make every decision. Claude Code eliminates boilerplate, configuration, and TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours\\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved days of design work\\n2. **LLMs excel at structure, watch accuracy** - Fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack delivers** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy\\n- Add analytics (privacy-friendly)\\n\\nThe key win? **I can do all of that in Directus, without touching code.**\\n\\n\\n","date_updated":"2025-10-14T06:03:09.529Z"}	\N	\N
152	179	posts	8	{"id":8,"date_created":"2025-10-14T06:27:10.440Z","date_updated":"2025-10-14T06:48:12.893Z","title":"Building Production Sites with AI: Why Curation Beats Automation","published":true,"content":"# Building Production Sites with AI: Why Curation Beats Automation\\n\\nOne day of prompting. Production-ready portfolio. But not because AI is magic—because I knew what to ask for.\\n\\n## The Setup\\n\\n**What I saw:** v0.dev templates at an AWS event. Beautiful. Locked to Vercel's framework.\\n\\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\\n\\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\\n\\n**Why it worked:** Curation and taste. Not because AI figured it out.\\n\\n## What AI Gives You Without Direction\\n\\nLeft to its own devices, Claude Code suggests:\\n\\n**The default stack:**\\n- Express (because it's popular)\\n- Basic JavaScript (because it's simple)\\n- Hardcoded data (because it works)\\n- Generic placeholders everywhere\\n\\n**What you get:** Something that runs. Nothing you'd ship.\\n\\nThis is the trap: AI coding tools *work*, but they optimize for \\"runs quickly\\" not \\"production-grade.\\"\\n\\n## What Changes with Curation\\n\\nWhen you know what exists, you can prompt differently.\\n\\n**Without curation:**\\n> \\"Build me a portfolio site\\"\\n\\nResult: Next.js with hardcoded content. Generic. Forgettable.\\n\\n**With curation:**\\n> \\"I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe.\\"\\n\\nResult: Production architecture in a day.\\n\\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\\n\\n## Where I Actually Learned\\n\\n### Tech Events\\n\\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: \\"Great UI, wrong stack for my needs.\\"\\n\\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\\n\\n### The Internet Annals\\n\\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\\n\\nNot tutorials. Real people discussing real trade-offs.\\n\\n### Small Experiments with Claude Code\\n\\nBuilding throwaway projects:\\n- \\"Show me how Directus works\\"\\n- \\"What's the Hono API surface look like?\\"\\n- \\"How does Astro handle dynamic routes?\\"\\n\\nRudimentary understanding. Just enough to know what's possible.\\n\\n## The Moment of Synthesis\\n\\nv0.dev templates are beautiful. But I wanted:\\n- Astro (better for content than Next.js)\\n- Self-hosted (not Vercel-locked)\\n- Directus (better admin UI than competitors)\\n- Hono (lighter than Express)\\n\\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\\n\\n## What One Day of Prompting Looks Like\\n\\n### Morning: The Conversion\\n\\n**Me:** \\"This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework.\\"\\n\\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\\n\\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\\n\\n### Afternoon: The Integration\\n\\n**Me:** \\"Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API.\\"\\n\\n**Claude Code:** Implements the adapter. Type-safe throughout.\\n\\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\\n\\n### Evening: The Deployment\\n\\n**Me:** \\"Docker Compose. Frontend, API, Directus. Healthchecks so they start in order.\\"\\n\\n**Claude Code:** Generates docker-compose.yml. We debug networking.\\n\\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\\n\\n## The LLM-Driven Issue Loop\\n\\nThis is where Sonnet 4.5 shines:\\n\\n**Pattern:**\\n1. Build a feature\\n2. Test it\\n3. Hit an error\\n4. Paste error to Claude Code\\n5. It suggests fix\\n6. Repeat\\n\\n**Example:**\\n- Docker services can't reach each other\\n- Paste error logs\\n- \\"Add them all to the same network\\"\\n- Works\\n\\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\\n\\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\\n\\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\\n\\n## What Curation Actually Means\\n\\n### 1. Knowing What Exists\\n\\nI can't ask for Hono if I don't know it exists. I learned it from:\\n- Tech event hallway conversation\\n- Seeing it on a \\"lightweight Node frameworks\\" list\\n- Building a throwaway API to understand it\\n\\n**The work:** Self-directed learning. Tech events. Experimentation.\\n\\n### 2. Understanding Trade-offs\\n\\nWhen Claude Code suggests Express, I know to push back: \\"What about Hono?\\"\\n\\nWhen it suggests Strapi, I counter with: \\"Directus has a better admin UI.\\"\\n\\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\\n\\n### 3. Recognizing Good Architecture\\n\\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\\n- Separates concerns\\n- Keeps Astro pages clean\\n- Makes CMS swappable\\n\\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\\n\\n### 4. Directing, Not Just Accepting\\n\\nDefault: \\"Build me X\\" → AI chooses everything\\n\\nCurated: \\"I want A, B, C integrated. Show me how\\" → You choose, AI implements\\n\\n**The difference:** Agency. You're in control.\\n\\n## Why This Moment Matters\\n\\n### The Timing\\n\\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\\n\\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\\n\\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\\n\\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\\n\\n### What Makes This Reproducible\\n\\nNot \\"use these exact tools.\\"\\n\\nBut: **Build your curation muscle, then execute with AI.**\\n\\n**How to build curation:**\\n1. Go to tech events (see tools demoed, hear hallway chatter)\\n2. Dig through forums (understand why people choose X over Y)\\n3. Build small experiments (gain rudimentary understanding)\\n4. Develop taste (know when \\"good enough\\" vs \\"production-grade\\")\\n\\n**Then when Sonnet 4.5 (or better) exists:**\\n- You can name what you want\\n- AI handles implementation details\\n- One day of focused work = production site\\n\\n## The Honest Comparison\\n\\n### Without Curation\\n**Prompt:** \\"Build me a portfolio site\\"\\n\\n**Result:** Express + basic JS + placeholders\\n\\n**Time to production:** Weeks of refactoring to make it real\\n\\n### With Curation\\n**Prompt:** \\"Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment.\\"\\n\\n**Result:** Production-grade architecture from day one\\n\\n**Time to production:** One day of focused prompting\\n\\n**The difference:** I did the learning beforehand. AI does the implementation now.\\n\\n## What You Actually Need to Learn\\n\\n**Not from AI:**\\n- What tools exist in the ecosystem\\n- Why people choose specific tools\\n- Trade-offs between options\\n- What \\"production-grade\\" looks like\\n\\n**From AI:**\\n- How to integrate specific tools\\n- Configuration syntax\\n- Implementation patterns\\n- Fixing specific errors\\n\\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\\n\\n## The Pattern\\n\\n**Phase 1: Self-Directed Learning**\\n- Attend tech events\\n- Read forums and GitHub issues\\n- Experiment with tools in isolation\\n- Develop opinions about trade-offs\\n\\n**Phase 2: Small Experiments**\\n- Build throwaway projects with Claude Code\\n- Gain rudimentary understanding\\n- Learn what's possible, what's hard\\n\\n**Phase 3: Recognition**\\n- \\"I know what I want to build\\"\\n- \\"I know which tools fit together\\"\\n- \\"I can direct an AI toward this vision\\"\\n\\n**Phase 4: Execution**\\n- One day of focused prompting\\n- LLM-driven issue loop (error → fix → repeat)\\n- Production-grade result\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Timeline:**\\n- Months of learning (events, experiments, forums)\\n- One day of building (prompting + iteration)\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\\n\\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\\n\\n## The Real Unlock\\n\\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\\n\\n**2025:** You need to know what to build and why. AI builds it for you.\\n\\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\\n\\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\\n\\n**When AI amplifies it:** When you can say \\"I want A, B, C integrated\\" and the AI handles implementation.\\n\\nThe tools haven't changed. The leverage has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\\n"}	{"title":"Building Production Sites with AI: Why Curation Beats Automation","content":"# Building Production Sites with AI: Why Curation Beats Automation\\n\\nOne day of prompting. Production-ready portfolio. But not because AI is magic—because I knew what to ask for.\\n\\n## The Setup\\n\\n**What I saw:** v0.dev templates at an AWS event. Beautiful. Locked to Vercel's framework.\\n\\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\\n\\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\\n\\n**Why it worked:** Curation and taste. Not because AI figured it out.\\n\\n## What AI Gives You Without Direction\\n\\nLeft to its own devices, Claude Code suggests:\\n\\n**The default stack:**\\n- Express (because it's popular)\\n- Basic JavaScript (because it's simple)\\n- Hardcoded data (because it works)\\n- Generic placeholders everywhere\\n\\n**What you get:** Something that runs. Nothing you'd ship.\\n\\nThis is the trap: AI coding tools *work*, but they optimize for \\"runs quickly\\" not \\"production-grade.\\"\\n\\n## What Changes with Curation\\n\\nWhen you know what exists, you can prompt differently.\\n\\n**Without curation:**\\n> \\"Build me a portfolio site\\"\\n\\nResult: Next.js with hardcoded content. Generic. Forgettable.\\n\\n**With curation:**\\n> \\"I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe.\\"\\n\\nResult: Production architecture in a day.\\n\\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\\n\\n## Where I Actually Learned\\n\\n### Tech Events\\n\\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: \\"Great UI, wrong stack for my needs.\\"\\n\\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\\n\\n### The Internet Annals\\n\\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\\n\\nNot tutorials. Real people discussing real trade-offs.\\n\\n### Small Experiments with Claude Code\\n\\nBuilding throwaway projects:\\n- \\"Show me how Directus works\\"\\n- \\"What's the Hono API surface look like?\\"\\n- \\"How does Astro handle dynamic routes?\\"\\n\\nRudimentary understanding. Just enough to know what's possible.\\n\\n## The Moment of Synthesis\\n\\nv0.dev templates are beautiful. But I wanted:\\n- Astro (better for content than Next.js)\\n- Self-hosted (not Vercel-locked)\\n- Directus (better admin UI than competitors)\\n- Hono (lighter than Express)\\n\\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\\n\\n## What One Day of Prompting Looks Like\\n\\n### Morning: The Conversion\\n\\n**Me:** \\"This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework.\\"\\n\\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\\n\\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\\n\\n### Afternoon: The Integration\\n\\n**Me:** \\"Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API.\\"\\n\\n**Claude Code:** Implements the adapter. Type-safe throughout.\\n\\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\\n\\n### Evening: The Deployment\\n\\n**Me:** \\"Docker Compose. Frontend, API, Directus. Healthchecks so they start in order.\\"\\n\\n**Claude Code:** Generates docker-compose.yml. We debug networking.\\n\\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\\n\\n## The LLM-Driven Issue Loop\\n\\nThis is where Sonnet 4.5 shines:\\n\\n**Pattern:**\\n1. Build a feature\\n2. Test it\\n3. Hit an error\\n4. Paste error to Claude Code\\n5. It suggests fix\\n6. Repeat\\n\\n**Example:**\\n- Docker services can't reach each other\\n- Paste error logs\\n- \\"Add them all to the same network\\"\\n- Works\\n\\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\\n\\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\\n\\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\\n\\n## What Curation Actually Means\\n\\n### 1. Knowing What Exists\\n\\nI can't ask for Hono if I don't know it exists. I learned it from:\\n- Tech event hallway conversation\\n- Seeing it on a \\"lightweight Node frameworks\\" list\\n- Building a throwaway API to understand it\\n\\n**The work:** Self-directed learning. Tech events. Experimentation.\\n\\n### 2. Understanding Trade-offs\\n\\nWhen Claude Code suggests Express, I know to push back: \\"What about Hono?\\"\\n\\nWhen it suggests Strapi, I counter with: \\"Directus has a better admin UI.\\"\\n\\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\\n\\n### 3. Recognizing Good Architecture\\n\\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\\n- Separates concerns\\n- Keeps Astro pages clean\\n- Makes CMS swappable\\n\\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\\n\\n### 4. Directing, Not Just Accepting\\n\\nDefault: \\"Build me X\\" → AI chooses everything\\n\\nCurated: \\"I want A, B, C integrated. Show me how\\" → You choose, AI implements\\n\\n**The difference:** Agency. You're in control.\\n\\n## Why This Moment Matters\\n\\n### The Timing\\n\\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\\n\\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\\n\\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\\n\\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\\n\\n### What Makes This Reproducible\\n\\nNot \\"use these exact tools.\\"\\n\\nBut: **Build your curation muscle, then execute with AI.**\\n\\n**How to build curation:**\\n1. Go to tech events (see tools demoed, hear hallway chatter)\\n2. Dig through forums (understand why people choose X over Y)\\n3. Build small experiments (gain rudimentary understanding)\\n4. Develop taste (know when \\"good enough\\" vs \\"production-grade\\")\\n\\n**Then when Sonnet 4.5 (or better) exists:**\\n- You can name what you want\\n- AI handles implementation details\\n- One day of focused work = production site\\n\\n## The Honest Comparison\\n\\n### Without Curation\\n**Prompt:** \\"Build me a portfolio site\\"\\n\\n**Result:** Express + basic JS + placeholders\\n\\n**Time to production:** Weeks of refactoring to make it real\\n\\n### With Curation\\n**Prompt:** \\"Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment.\\"\\n\\n**Result:** Production-grade architecture from day one\\n\\n**Time to production:** One day of focused prompting\\n\\n**The difference:** I did the learning beforehand. AI does the implementation now.\\n\\n## What You Actually Need to Learn\\n\\n**Not from AI:**\\n- What tools exist in the ecosystem\\n- Why people choose specific tools\\n- Trade-offs between options\\n- What \\"production-grade\\" looks like\\n\\n**From AI:**\\n- How to integrate specific tools\\n- Configuration syntax\\n- Implementation patterns\\n- Fixing specific errors\\n\\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\\n\\n## The Pattern\\n\\n**Phase 1: Self-Directed Learning**\\n- Attend tech events\\n- Read forums and GitHub issues\\n- Experiment with tools in isolation\\n- Develop opinions about trade-offs\\n\\n**Phase 2: Small Experiments**\\n- Build throwaway projects with Claude Code\\n- Gain rudimentary understanding\\n- Learn what's possible, what's hard\\n\\n**Phase 3: Recognition**\\n- \\"I know what I want to build\\"\\n- \\"I know which tools fit together\\"\\n- \\"I can direct an AI toward this vision\\"\\n\\n**Phase 4: Execution**\\n- One day of focused prompting\\n- LLM-driven issue loop (error → fix → repeat)\\n- Production-grade result\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Timeline:**\\n- Months of learning (events, experiments, forums)\\n- One day of building (prompting + iteration)\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\\n\\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\\n\\n## The Real Unlock\\n\\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\\n\\n**2025:** You need to know what to build and why. AI builds it for you.\\n\\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\\n\\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\\n\\n**When AI amplifies it:** When you can say \\"I want A, B, C integrated\\" and the AI handles implementation.\\n\\nThe tools haven't changed. The leverage has.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\\n","date_updated":"2025-10-14T06:48:12.893Z"}	\N	\N
156	187	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T06:58:50.652Z","title":"The Velocity Shift: Building My Portfolio with Claude Code in 2025","published":true,"content":"# The Velocity Shift: Building My Portfolio with Claude Code in 2025\\n\\nTen hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (I knew content-first > full SPA)\\n- Directus over Strapi (better admin UI, saw it demoed)\\n- Hono over Express (lighter, saw it mentioned at a meetup)\\n- Docker Compose over Kubernetes (right scale for homelab)\\n- Cloudflare Tunnels over nginx (simpler, more secure)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n"}	{"title":"The Velocity Shift: Building My Portfolio with Claude Code in 2025","content":"# The Velocity Shift: Building My Portfolio with Claude Code in 2025\\n\\nTen hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (I knew content-first > full SPA)\\n- Directus over Strapi (better admin UI, saw it demoed)\\n- Hono over Express (lighter, saw it mentioned at a meetup)\\n- Docker Compose over Kubernetes (right scale for homelab)\\n- Cloudflare Tunnels over nginx (simpler, more secure)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n","date_updated":"2025-10-14T06:58:50.652Z"}	\N	\N
159	190	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T07:02:18.094Z","title":"Building My Portfolio with Claude Code","published":true,"content":"Ten hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (I knew content-first > full SPA)\\n- Directus over Strapi (asked Claude once about proper CMS options)\\n- Hono over Express (lighter, saw it mentioned at a meetup)\\n- Docker Compose over Kubernetes (right scale for homelab)\\n- Cloudflare Tunnels over nginx (simpler, more secure)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n"}	{"content":"Ten hours of active work. Production site deployed. This isn't about what AI can do—it's about how the workflow fundamentally changed.\\n\\n## The Numbers Everyone Quotes\\n\\n**2023 approach:** 50+ hours minimum\\n- Component migration: 20 hours\\n- API setup and debugging: 10 hours\\n- Docker configuration: 15 hours\\n- TypeScript interface alignment: 8 hours\\n\\n**2025 with AI:** ~10 hours active work\\n- Template conversion: 2 hours\\n- Directus integration: 3 hours\\n- Deployment setup: 2 hours\\n- Refinement: 3 hours\\n\\n**The math:** 5x faster. But that's not the interesting part.\\n\\n## What Actually Changed\\n\\n### The Old Loop: Research → Implement → Debug\\n\\n**2023 workflow:**\\n1. \\"How do I convert React to Astro?\\" → Read docs for 2 hours\\n2. Convert first component → Breaks\\n3. Google the error → StackOverflow thread from 2021\\n4. Try fix → Different error\\n5. Repeat 20 times\\n\\n**Hours spent:** Most of it on steps 1, 3, and 5. Actually writing code is the minority.\\n\\n### The New Loop: Describe → Iterate → Fix\\n\\n**2025 workflow:**\\n1. \\"Convert this v0.dev template to Astro\\" → Claude Code does it\\n2. Test → Something breaks\\n3. Paste error → Claude Code fixes it\\n4. Move on\\n\\n**Hours spent:** Mostly on deciding *what* to build. Implementation is the minority.\\n\\n**The shift:** From \\"how do I do this?\\" to \\"make this work.\\"\\n\\n## The Practical Reality\\n\\n### What I Actually Did\\n\\n**Morning:** Picked Felix's v0.dev template. Knew I wanted Astro (not Next.js), Directus (not hardcoded content), self-hosted (not Vercel).\\n\\nThese weren't AI suggestions. These were choices I made from months of seeing tools at tech events, reading comparisons, trying experiments.\\n\\n**Afternoon:** Told Claude Code: \\"Convert to Astro. Integrate Directus. Use Hono for the API layer.\\"\\n\\nI named the tools. I directed the architecture. Claude Code implemented it.\\n\\n**Evening:** Hit errors. Pasted them. Claude Code fixed them. Deployed.\\n\\n### What Claude Code Actually Did\\n\\n**Real examples from the session:**\\n\\n```\\nMe: \\"Docker services can't reach each other\\"\\nClaude Code: \\"Add them all to the same network. Here's the config.\\"\\n→ Works immediately\\n```\\n\\n```\\nMe: \\"TypeScript complaining about Directus response types\\"\\nClaude Code: \\"Your interface doesn't match. Here's the fix.\\"\\n→ Build succeeds\\n```\\n\\n```\\nMe: \\"Astro routes aren't loading Directus content\\"\\nClaude Code: \\"You need a content adapter. Here's the pattern.\\"\\n→ Pages render\\n```\\n\\n**The pattern:** I hit walls. Claude Code removes them. Fast.\\n\\n### What I Still Decided\\n\\nEvery architectural choice:\\n- Astro over Next.js (I knew content-first > full SPA)\\n- Directus over Strapi (asked Claude once about proper CMS options)\\n- Hono over Express (lighter, saw it mentioned at a meetup)\\n- Docker Compose over Kubernetes (right scale for homelab)\\n- Cloudflare Tunnels over nginx (simpler, more secure)\\n\\nEvery content decision:\\n- Which projects to feature\\n- How to describe my role accurately\\n- What technologies to highlight\\n- When \\"good enough\\" beats \\"perfect\\"\\n\\n**Claude Code didn't make these calls.** It executed them.\\n\\n## The Conversation Patterns That Made It Fast\\n\\n### Pattern 1: Specific Requests, Not Open-Ended\\n\\n**Slow:**\\n> \\"Build me a portfolio\\"\\n\\nClaude Code gives you generic Next.js + basic placeholders. You spend hours refactoring.\\n\\n**Fast:**\\n> \\"I have this v0.dev template. Convert it to Astro. Keep the design system, swap the framework.\\"\\n\\nClaude Code knows exactly what to do. Two hours later, it's done.\\n\\n**Why:** Specificity eliminates back-and-forth.\\n\\n### Pattern 2: Error-Driven Fixes\\n\\n**The old way:** Hit error → Google → StackOverflow → Try fix → Different error → Repeat\\n\\n**The new way:** Hit error → Paste to Claude Code → Get fix → Works\\n\\n**Real example from today:**\\n\\n```\\nDocker error: \\"network homelab-network declared as external, but could not be found\\"\\n\\nOld approach: 30 minutes searching Docker networking docs\\nNew approach: Paste error, Claude Code says \\"Create the network first: docker network create homelab-network\\"\\nTime: 30 seconds\\n```\\n\\n**Multiply by 20 errors:** That's 10 hours saved just on debugging.\\n\\n### Pattern 3: Iterative Refinement\\n\\n**The workflow:**\\n\\n```\\nMe: \\"Add a category field to work projects\\"\\nClaude Code: Updates schema, migrations, TypeScript types, all components\\n→ Test: Works\\n\\nMe: \\"Social links look cluttered\\"\\nClaude Code: Simplifies to minimal design\\n→ Test: Better\\n\\nMe: \\"CS Club description overstates my role\\"\\nClaude Code: Rewrites with accurate framing\\n→ Review: Ship it\\n```\\n\\nEach iteration: 5-10 minutes. No context switching. No \\"where did I leave off?\\"\\n\\n**The multiplier:** 10 small iterations in an hour vs 10 small iterations in a day.\\n\\n## What's Actually Hard in 2025\\n\\nNot the code. The decisions.\\n\\n### Easy (Claude Code Handles It)\\n- TypeScript interface alignment across API boundaries\\n- Docker networking and healthchecks\\n- Astro dynamic route patterns\\n- Directus SDK setup and queries\\n- Environment variable configuration\\n\\n### Still Hard (You Handle It)\\n- **Knowing what exists:** Can't ask for Hono if you don't know it exists\\n- **Evaluating trade-offs:** Should this be normalized or denormalized?\\n- **Content accuracy:** AI writes well, but overstates. You fact-check.\\n- **Aesthetic judgment:** Is this minimal or sparse? Ship or iterate?\\n- **Strategic decisions:** What's actually worth building?\\n\\n**The honest truth:** Building is 5x faster. Deciding what to build still takes the same time.\\n\\n## The Workflow Transformation\\n\\n### Before AI\\n**Your time:**\\n- 20% deciding what to build\\n- 80% implementing and debugging\\n\\n**Your skill:**\\n- Knowing how to implement\\n- Debugging when it breaks\\n- Reading documentation\\n\\n### With AI\\n**Your time:**\\n- 70% deciding what to build\\n- 30% implementing and debugging\\n\\n**Your skill:**\\n- Knowing what exists and fits together\\n- Directing AI toward good architecture\\n- Evaluating whether solutions are solid\\n\\n**The shift:** From \\"can I build this?\\" to \\"should I build this?\\"\\n\\n## The Real Advantage\\n\\nIt's not that Claude Code is fast. It's that **you stay in flow.**\\n\\n**Old workflow:**\\n1. Write code for 20 minutes\\n2. Hit error\\n3. Context switch to Google\\n4. Read 5 StackOverflow threads\\n5. Try a fix\\n6. Different error\\n7. Back to Google\\n8. 2 hours later: forgot what you were building\\n\\n**New workflow:**\\n1. Describe what you want\\n2. Claude Code implements\\n3. Hit error\\n4. Paste error\\n5. Claude Code fixes\\n6. Continue\\n\\n**No context switching.** That's the real speed boost.\\n\\n## The Homelab Reality\\n\\nRunning this on a Debian server in my closet with Cloudflare Tunnels means:\\n\\n**Old approach:** Weeks learning nginx, SSL certificates, dynamic DNS, port forwarding, firewall rules.\\n\\n**New approach:** \\"Set up Cloudflare Tunnel for this Docker stack\\" → Claude Code generates config → 30 minutes deployed.\\n\\n**The unlock:** Self-hosting is viable again. Not because it's easier, but because setup time went from weeks to hours.\\n\\n## Lessons From 10 Hours\\n\\n1. **Start with good design** - Felix's template saved me from design decisions\\n2. **Name your tools** - Claude Code is fast when you direct it specifically\\n3. **Paste errors immediately** - Don't debug yourself first\\n4. **Iterate in public** - Ship, then refine based on what breaks\\n5. **Verify claims** - AI writes confidently. You fact-check.\\n\\n## What This Means for You\\n\\n### If You Want to Try This\\n\\n**You need:**\\n- Enough context to name tools (Astro, Directus, Hono)\\n- Ability to evaluate whether architecture is solid\\n- Willingness to iterate publicly\\n- Sonnet 4.5 or better\\n\\n**You don't need:**\\n- Deep expertise in each tool\\n- Years of full-stack experience\\n- Perfect architecture on first try\\n\\n**The threshold lowered:** You need to know what exists and fits together. You don't need to know how to implement it all.\\n\\n### The Honest Timeline\\n\\n**Months before:** Learning what exists (tech events, forums, small experiments)\\n\\n**Day of building:**\\n- Hour 1-2: Template conversion to Astro\\n- Hour 3-5: Directus integration and content adapter\\n- Hour 6-7: Docker Compose and deployment\\n- Hour 8-10: Refinement and accuracy fixes\\n\\n**The truth:** 10 hours is real. But it's built on months of context.\\n\\n## The Result\\n\\n**Live:** https://b28.dev\\n\\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\\n\\n**Built in:** 10 hours active work\\n\\n**Deployed:** Self-hosted homelab\\n\\n**CMS-backed:** Updates without code changes\\n\\n**The takeaway:** Building is 5x faster. But you still make every decision.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** From \\"how do I build this?\\" to \\"make this work.\\"\\n","date_updated":"2025-10-14T07:02:18.094Z"}	\N	\N
131	148	work_projects	8	{"id":8,"status":"published","title":"Univar Solutions - Data Engineering","slug":"potion-data-engineering","company":"Potion","role":"Data Analyst (Contract)","year":"2022","duration":"Contract","description":"Contract data analyst for Potion, a software consultancy serving Univar Solutions. Built data reconciliation pipeline for chemical formula database and introduced Jupyter notebooks to annotation team.","content":"## Challenge\\n\\nChemical formulation database at Univar Solutions needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\\n\\n## Solution\\n\\n### Data Pipeline\\n- Built reconciliation system matching outdated names to original IDs\\n- Enabled bidirectional sync between golden dataset and production DB\\n- Automated cleanup and consolidation of redundant labels\\n\\n### Team Enablement\\n- Introduced Jupyter notebooks to annotation team\\n- Created tools for efficient data cleanup\\n- Trained team on data engineering best practices\\n\\n## Impact\\n- Saved hundreds of hours of manual work\\n- Made previously impossible database updates feasible\\n- Improved data quality for Univar Solutions chemical supply network\\n\\n## Technologies\\n- Data engineering and ETL\\n- Database reconciliation algorithms\\n- Jupyter for collaborative data work\\n\\n*Contract role through Potion, providing services to Univar Solutions*","technologies":["Python","Jupyter","Data Engineering","ETL","Database Systems"],"featured":true,"order":2,"team":null,"live_url":null,"case_study_url":null,"category":"employment"}	{"order":2}	\N	\N
132	149	work_projects	5	{"id":5,"status":"published","title":"Piper - STEM Learning Platform","slug":"piper","company":"Piper, Inc.","role":"Software Engineer","year":"2018-2021","duration":"3 years 5 months","description":"Full-stack engineer on STEM learning platform combining hardware and software. Key contributor to expansion pack release, PiperStory (Minecraft-based game mode), and PiperCode (Blockly/Scratch teaching tool).","content":"## Role & Responsibilities\\n\\nFull-stack engineer on Python-based STEM learning platform for K-12 education, combining Raspberry Pi hardware with custom software.\\n\\n## Key Projects\\n\\n### PiperStory Game Mode\\n- Raspberry Pi-based modded Minecraft system\\n- Built on top of Minecraft Pi Edition\\n- Created educational game experiences for kids learning electronics and programming\\n\\n### PiperCode Teaching Tool\\n- React-based Electron app using Blockly/Scratch\\n- Visual programming interface for kids to learn coding concepts\\n- Integrated with hardware projects\\n\\n### Expansion Pack (DLC)\\n- Key contributor to major content release as part of core dev team\\n- Improved customer engagement and retention\\n- Extended platform capabilities with new features\\n\\n### Infrastructure & Analytics\\n- **Analytics Dashboard**: Set up SQL and Amplitude for marketing, QA, and dev-ops intelligence\\n- **Survey System**: Developed FERPA-compliant web service using JavaScript, Google Apps Engine, and Firebase\\n- **Technical Blog**: Created content exploring CS and EE concepts through DIY projects\\n\\n## Impact\\n- Part of small team delivering STEM education to K-12 students nationwide\\n- Contributed to product development across hardware/software integration\\n- Built tools that made learning electronics and programming accessible to kids\\n\\n*Note: Piper is no longer in production as of 2021*","technologies":["Python","JavaScript","SQL","Firebase","Google Apps Engine","Amplitude","Game Development"],"featured":true,"order":3,"team":null,"live_url":null,"case_study_url":null,"category":"employment"}	{"order":3}	\N	\N
133	150	work_projects	6	{"id":6,"status":"published","title":"IdeaWall - HCI Research","slug":"ideawall-research","company":"UC Davis Visualization Lab","role":"Research Assistant","year":"2015-2016","duration":"1 year 2 months","description":"Research assistant on ACM CSCW paper about AI-augmented creative collaboration. Contributed to user studies, Mandarin-to-English copyediting, and publication process for IdeaWall system.","content":"## Research Project\\n\\n**Published**: ACM Conference on Computer Supported Cooperative Work and Social Computing (CSCW '17)\\n\\n## Overview\\n\\nResearch assistant at UC Davis Visualization Lab working on IdeaWall, an intelligent system that augments verbal creative collaboration with real-time visual stimuli.\\n\\n## Contributions\\n\\n### User Studies\\n- Conducted and facilitated user testing sessions\\n- Helped coordinate study with 24 participants across 12 groups\\n- Collected and documented research data\\n\\n### Publication Support\\n- Mandarin-to-English copyediting for international collaboration\\n- Assisted with paper revision and submission process\\n- Contributed to getting paper accepted at competitive HCI venue\\n\\n### Technical Support\\n- Assisted with real-time speech processing and information extraction system\\n- Supported web search integration for contextual materials\\n- Helped develop visual display system with three cognitive strategies\\n\\n## Research Impact\\n- Junior author on paper demonstrating effectiveness of AI-assisted collaboration tools\\n- Contributed to validating three cognitive strategies for visual facilitation\\n- Helped establish foundation for future intelligent groupware systems\\n\\n## Skills Developed\\n- Research methodology and user testing\\n- Academic writing and publication process\\n- Cross-cultural collaboration and translation\\n- Human-computer interaction design","technologies":["HCI Research","Real-time Processing","User Studies","Data Visualization","Academic Writing"],"featured":true,"order":4,"team":null,"live_url":null,"case_study_url":"http://dl.acm.org/citation.cfm?id=2998208","category":"research"}	{"order":4}	\N	\N
134	153	profile	1	{"id":1,"full_name":"John Chen","first_name":"John","last_name":"Chen","title":"Creative Software Engineer","description":"Independent Software Engineer building AI-powered applications and fostering tech communities. Focused on rapid prototyping, LLM integration, and full-stack development.","email":"john.hk.chen@gmail.com","location":"San Francisco, CA","portfolio_year":"2025","availability":true,"availability_text":"Open to work — AI/ML, Full Stack, Developer Relations","current_role_title":"Independent Software Engineer","current_role_company":"Self-Employed","current_role_duration":"2020 — Present","work_section_title":"Selected Work","work_section_date_range":"2015 — Present","connect_title":"Let's Connect","connect_description":"Always interested in new opportunities, collaborations, and conversations about AI, developer tools, and community building. Available for full-time roles, contract work, and technical consulting.","footer_copyright":"John Chen","footer_attribution":"Built with Astro, Hono, Directus & Claude Code. Design by Felix Macaspac","footer_year":"2025"}	{"description":"Independent Software Engineer building AI-powered applications and fostering tech communities. Focused on rapid prototyping, LLM integration, and full-stack development.","current_role_title":"Independent Software Engineer","current_role_company":"Self-Employed","current_role_duration":"2020 — Present","work_section_date_range":"2015 — Present","footer_attribution":"Built with Astro, Hono, Directus & Claude Code. Design by Felix Macaspac"}	\N	\N
135	156	posts	7	{"title":"Building My Portfolio with Claude Code in 2025","content":"# Building My Portfolio with Claude Code in 2025\\n\\n**TL;DR**: Took a v0.dev template, had Claude Code migrate it to Astro+Hono+Directus, set up a Debian homelab, and deployed everything - all in a fraction of the time it would have taken even 2 years ago.\\n\\n## Why 2025 is Different\\n\\nThis project would have been a month-long ordeal in 2023. In 2025, with Claude Code as my development partner, it took days. Not because the fundamentals changed - JAMstack architecture is still JAMstack - but because the tooling finally caught up to the vision.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, but it was built for Vercel's ecosystem with hardcoded content.\\n\\n**The goal:** Turn it into a self-hosted CMS-backed site I could update without touching code.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nThis is where 2025 shines. Instead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces for hours, I described what I wanted and Claude Code:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup  \\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code helped me:\\n- Add category system to distinguish employment vs hackathons vs research\\n- Fix chronological ordering in work history\\n- Correct exaggerated claims and dates\\n- Update descriptions for accuracy\\n- Implement minimalist social link design\\n- Add template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n✅ **Cost** - One-time hardware, no monthly fees\\n✅ **Learning** - Understand every layer of the stack\\n✅ **Privacy** - My data stays on my hardware\\n✅ **Flexibility** - Can run whatever services I want\\n\\nCloudflare Tunnels solved the hard part (HTTPS, no port forwarding, DDoS protection) while keeping everything local.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration  \\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I had to correct exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, \\n#              patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"  \\n# Claude Code: Rewrites to emphasize supporting student leaders\\n#              while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about Claude Code replacing me - it's about removing friction. I still make every decision, but I don't waste hours on boilerplate, configuration, or TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours  \\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved me days of design work\\n2. **LLMs are great at structure, watch accuracy** - Had to fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack is real** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy  \\n- Add analytics (privacy-friendly)\\n\\nBut the key win? **I can do all of that in Directus, without touching code.**\\n\\n---\\n\\n*Built with Astro, Hono, Directus & Claude Code. Design by Felix Macaspac.*\\n","published":true}	{"title":"Building My Portfolio with Claude Code in 2025","content":"# Building My Portfolio with Claude Code in 2025\\n\\n**TL;DR**: Took a v0.dev template, had Claude Code migrate it to Astro+Hono+Directus, set up a Debian homelab, and deployed everything - all in a fraction of the time it would have taken even 2 years ago.\\n\\n## Why 2025 is Different\\n\\nThis project would have been a month-long ordeal in 2023. In 2025, with Claude Code as my development partner, it took days. Not because the fundamentals changed - JAMstack architecture is still JAMstack - but because the tooling finally caught up to the vision.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, but it was built for Vercel's ecosystem with hardcoded content.\\n\\n**The goal:** Turn it into a self-hosted CMS-backed site I could update without touching code.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nThis is where 2025 shines. Instead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces for hours, I described what I wanted and Claude Code:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup  \\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code helped me:\\n- Add category system to distinguish employment vs hackathons vs research\\n- Fix chronological ordering in work history\\n- Correct exaggerated claims and dates\\n- Update descriptions for accuracy\\n- Implement minimalist social link design\\n- Add template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n✅ **Cost** - One-time hardware, no monthly fees\\n✅ **Learning** - Understand every layer of the stack\\n✅ **Privacy** - My data stays on my hardware\\n✅ **Flexibility** - Can run whatever services I want\\n\\nCloudflare Tunnels solved the hard part (HTTPS, no port forwarding, DDoS protection) while keeping everything local.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration  \\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I had to correct exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, \\n#              patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"  \\n# Claude Code: Rewrites to emphasize supporting student leaders\\n#              while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about Claude Code replacing me - it's about removing friction. I still make every decision, but I don't waste hours on boilerplate, configuration, or TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours  \\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved me days of design work\\n2. **LLMs are great at structure, watch accuracy** - Had to fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack is real** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy  \\n- Add analytics (privacy-friendly)\\n\\nBut the key win? **I can do all of that in Directus, without touching code.**\\n\\n---\\n\\n*Built with Astro, Hono, Directus & Claude Code. Design by Felix Macaspac.*\\n","published":true}	\N	\N
136	157	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T05:55:37.055Z","title":"Building My Portfolio with Claude Code in 2025","published":true,"content":"I added converted v0.dev Next.js template to Astro and deployed on a Debian home server. It takes hours, not weeks.\\n\\n## Why 2025 is Different\\n\\nThis project would have taken a month in 2023. In 2025, with Claude Code, it took days. The fundamentals haven't changed—JAMstack is still JAMstack—but the tooling finally works.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, built for Vercel with hardcoded content.\\n\\n**The goal:** Self-host it with a CMS. No code changes for updates.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nInstead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces, I described what I wanted. Claude Code handled:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup\\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code:\\n- Added category system to distinguish employment vs hackathons vs research\\n- Fixed chronological ordering in work history\\n- Corrected exaggerated claims and dates\\n- Updated descriptions for accuracy\\n- Implemented minimalist social link design\\n- Added template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n✅ **Cost** - One-time hardware, no monthly fees\\n✅ **Learning** - Understand every layer of the stack\\n✅ **Privacy** - My data stays on my hardware\\n✅ **Flexibility** - Can run whatever services I want\\n\\nCloudflare Tunnels solved the hard part: HTTPS, no port forwarding, DDoS protection.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration\\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I corrected exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"\\n# Claude Code: Rewrites to emphasize supporting student leaders while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about replacement—it's about removing friction. I make every decision. Claude Code eliminates boilerplate, configuration, and TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours\\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved days of design work\\n2. **LLMs excel at structure, watch accuracy** - Fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack delivers** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy\\n- Add analytics (privacy-friendly)\\n\\nThe key win? **I can do all of that in Directus, without touching code.**\\n\\n\\n"}	{"content":"I added converted v0.dev Next.js template to Astro and deployed on a Debian home server. It takes hours, not weeks.\\n\\n## Why 2025 is Different\\n\\nThis project would have taken a month in 2023. In 2025, with Claude Code, it took days. The fundamentals haven't changed—JAMstack is still JAMstack—but the tooling finally works.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, built for Vercel with hardcoded content.\\n\\n**The goal:** Self-host it with a CMS. No code changes for updates.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nInstead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces, I described what I wanted. Claude Code handled:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup\\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code:\\n- Added category system to distinguish employment vs hackathons vs research\\n- Fixed chronological ordering in work history\\n- Corrected exaggerated claims and dates\\n- Updated descriptions for accuracy\\n- Implemented minimalist social link design\\n- Added template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n✅ **Cost** - One-time hardware, no monthly fees\\n✅ **Learning** - Understand every layer of the stack\\n✅ **Privacy** - My data stays on my hardware\\n✅ **Flexibility** - Can run whatever services I want\\n\\nCloudflare Tunnels solved the hard part: HTTPS, no port forwarding, DDoS protection.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration\\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I corrected exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"\\n# Claude Code: Rewrites to emphasize supporting student leaders while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about replacement—it's about removing friction. I make every decision. Claude Code eliminates boilerplate, configuration, and TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours\\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved days of design work\\n2. **LLMs excel at structure, watch accuracy** - Fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack delivers** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy\\n- Add analytics (privacy-friendly)\\n\\nThe key win? **I can do all of that in Directus, without touching code.**\\n\\n\\n","date_updated":"2025-10-14T05:55:37.055Z"}	\N	\N
137	158	profile	1	{"id":1,"full_name":"John Chen","first_name":"John","last_name":"Chen","title":"Creative Software Engineer","description":"Building AI-powered applications with LLMs and agentic systems. Full-stack engineer specializing in rapid prototyping and production ML integrations.","email":"john.hk.chen@gmail.com","location":"San Francisco, CA","portfolio_year":"2025","availability":true,"availability_text":"Open to work — AI/ML Engineer","current_role_title":"Independent Software Engineer","current_role_company":"Self-Employed","current_role_duration":"2020 — Present","work_section_title":"Selected Work","work_section_date_range":"2015 — Present","connect_title":"Let's Connect","connect_description":"Open for AI/ML roles, contract work, and technical consulting on LLM/agentic applications.","footer_copyright":"John Chen","footer_attribution":"Built with Astro, Hono, Directus & Claude. Design by v0 + Felix M.","footer_year":"2025"}	{"description":"Building AI-powered applications with LLMs and agentic systems. Full-stack engineer specializing in rapid prototyping and production ML integrations.","availability_text":"Open to work — AI/ML Engineer","connect_description":"Open for AI/ML roles, contract work, and technical consulting on LLM/agentic applications.","footer_attribution":"Built with Astro, Hono, Directus & Claude. Design by v0 + Felix M."}	\N	\N
138	159	skills	13	{"id":13,"name":"Node.js","category":"backend","proficiency":"expert","order":13,"featured":false}	{"featured":false}	\N	\N
139	160	skills	2	{"id":2,"name":"OpenAI","category":"aiml","proficiency":"expert","order":2,"featured":true}	{"name":"OpenAI"}	\N	\N
143	164	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T06:01:43.701Z","title":"Building My Portfolio with Claude Code in 2025","published":true,"content":"I added converted v0.dev Next.js template to Astro and deployed on a Debian home server. It takes hours, not weeks.\\n\\n## Why 2025 is Different\\n\\nThis project would have taken a month in 2023. In 2025, with Claude Code, it took days. The fundamentals haven't changed—JAMstack is still JAMstack—but the tooling finally works.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, built for Vercel with hardcoded content.\\n\\n**The goal:** Self-host it with a CMS. No code changes for updates.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nInstead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces, I described what I wanted. Claude Code handled:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup\\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code:\\n- Added category system to distinguish employment vs hackathons vs research\\n- Fixed chronological ordering in work history\\n- Corrected exaggerated claims and dates\\n- Updated descriptions for accuracy\\n- Implemented minimalist social link design\\n- Added template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n\\n✅ **Cost** - One-time hardware, no monthly fees\\n\\n✅ **Learning** - Understand every layer of the stack\\n\\n✅ **Privacy** - My data stays on my hardware\\n\\n✅ **Flexibility** - Can run whatever services I want\\n\\n\\nCloudflare Tunnels solved the hard part: HTTPS, no port forwarding, DDoS protection.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration\\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I corrected exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"\\n# Claude Code: Rewrites to emphasize supporting student leaders while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about replacement—it's about removing friction. I make every decision. Claude Code eliminates boilerplate, configuration, and TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours\\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved days of design work\\n2. **LLMs excel at structure, watch accuracy** - Fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack delivers** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy\\n- Add analytics (privacy-friendly)\\n\\nThe key win? **I can do all of that in Directus, without touching code.**\\n\\n\\n"}	{"content":"I added converted v0.dev Next.js template to Astro and deployed on a Debian home server. It takes hours, not weeks.\\n\\n## Why 2025 is Different\\n\\nThis project would have taken a month in 2023. In 2025, with Claude Code, it took days. The fundamentals haven't changed—JAMstack is still JAMstack—but the tooling finally works.\\n\\n## The Starting Point\\n\\nI started with Felix Macaspac's minimalist portfolio template from v0.dev (https://v0.app/templates/minimalist-portfolio-1DPeR9dunMc). Beautiful design, built for Vercel with hardcoded content.\\n\\n**The goal:** Self-host it with a CMS. No code changes for updates.\\n\\n## The Stack\\n\\n- **Frontend**: Astro (SSR) - Fast, content-focused, TypeScript\\n- **Backend API**: Hono (Node.js) - Minimal, edge-ready REST API\\n- **CMS**: Directus - Headless, PostgreSQL-backed, powerful admin UI\\n- **Infrastructure**: Docker Compose on Debian homelab\\n- **Deployment**: Cloudflare Tunnels (no port forwarding, HTTPS included)\\n- **Development Partner**: Claude Code\\n\\n## What Claude Code Did\\n\\nInstead of manually translating React components to Astro, configuring Docker networks, setting up API routes, and debugging TypeScript interfaces, I described what I wanted. Claude Code handled:\\n\\n### 1. Migration & Architecture\\n- Converted v0.dev template from Next.js to Astro\\n- Built TypeScript API layer with Hono\\n- Designed 4 Directus collections with proper schemas\\n- Connected everything with type-safe interfaces\\n\\n### 2. Infrastructure Setup\\n- Configured Docker Compose with proper networking\\n- Set up Cloudflare Tunnel integration\\n- Ensured proper environment variable handling\\n- Configured build processes for both frontend and API\\n\\n### 3. Content Migration\\n- Created Directus collections for: Profile, Work Projects, Skills, Social Links\\n- Populated with real data from multiple sources\\n- Set up proper relationships and filtering\\n\\n### 4. Iterative Refinement\\nToday alone, Claude Code:\\n- Added category system to distinguish employment vs hackathons vs research\\n- Fixed chronological ordering in work history\\n- Corrected exaggerated claims and dates\\n- Updated descriptions for accuracy\\n- Implemented minimalist social link design\\n- Added template attribution\\n\\n## The Homelab Advantage\\n\\nRunning this on a Debian server in my closet instead of Vercel means:\\n\\n✅ **Full control** - No vendor lock-in, no arbitrary limits\\n\\n✅ **Cost** - One-time hardware, no monthly fees\\n\\n✅ **Learning** - Understand every layer of the stack\\n\\n✅ **Privacy** - My data stays on my hardware\\n\\n✅ **Flexibility** - Can run whatever services I want\\n\\n\\nCloudflare Tunnels solved the hard part: HTTPS, no port forwarding, DDoS protection.\\n\\n## What's Actually Hard in 2025\\n\\n**Not hard anymore:**\\n- TypeScript migrations\\n- API boilerplate\\n- Docker configuration\\n- Schema design\\n- Component structure\\n\\n**Still requires thought:**\\n- Content strategy (what's actually worth showcasing?)\\n- Accuracy (Claude Code wrote great copy, but I corrected exaggerations)\\n- Design decisions (minimalism is harder than maximalism)\\n- Infrastructure maintenance (homelabs need care)\\n\\n## The Real Workflow\\n\\n```bash\\n# Me: \\"Add a category field to distinguish employment vs hackathons\\"\\n# Claude Code: Creates migration, updates TypeScript interfaces, patches all components, rebuilds containers\\n\\n# Me: \\"The CS Club description overstates my role\\"\\n# Claude Code: Rewrites to emphasize supporting student leaders while highlighting website SEO achievement\\n\\n# Me: \\"Social links look cluttered\\"\\n# Claude Code: Simplifies to just platform names with arrows\\n```\\n\\nThis isn't about replacement—it's about removing friction. I make every decision. Claude Code eliminates boilerplate, configuration, and TypeScript gymnastics.\\n\\n## The Numbers\\n\\n**What took days:**\\n- Initial v0.dev template selection: 30 minutes\\n- Claude Code migration to Astro: 2 hours\\n- Directus setup & content entry: 3 hours\\n- Refinement & accuracy fixes: 4 hours (today)\\n- Total: ~10 hours active work\\n\\n**What would have taken weeks in 2023:**\\n- Manual component migration: 20+ hours\\n- API setup & debugging: 10+ hours\\n- Docker configuration trial & error: 15+ hours\\n- TypeScript interface debugging: 8+ hours\\n- Total: 50+ hours minimum\\n\\n## Lessons Learned\\n\\n1. **Start with good design** - Felix's template saved days of design work\\n2. **LLMs excel at structure, watch accuracy** - Fact-check all claims\\n3. **Homelabs are viable again** - Cloudflare Tunnels made this practical\\n4. **JAMstack delivers** - This site is fast, cacheable, and scalable\\n5. **2025 is different** - What was hard in 2023 is now straightforward\\n\\n## The Result\\n\\n- ✅ Live at https://b28.dev\\n- ✅ CMS-backed (update without code changes)\\n- ✅ Self-hosted (no vendor fees)\\n- ✅ Type-safe across entire stack\\n- ✅ Accurate representation of my work\\n- ✅ Built in days, not weeks\\n\\n## What's Next\\n\\nNow that the foundation is solid:\\n- Add project screenshots and case studies\\n- Write more technical blog posts\\n- Expand skills taxonomy\\n- Add analytics (privacy-friendly)\\n\\nThe key win? **I can do all of that in Directus, without touching code.**\\n\\n\\n","date_updated":"2025-10-14T06:01:43.701Z"}	\N	\N
161	192	work_projects	2	{"id":2,"status":"published","title":"CS Club - Community Building & Education","slug":"cs-club-ccsf","company":"City College of San Francisco","role":"Officer","year":"2023-present","duration":"2 years+","description":"Treasurer and advisor for CS Club. Built https://ccsf-cs.club using Astro, achieving #1 Google ranking for CS clubs in SF. Led student teams attending tech events across the Bay Area.","content":"## Overview\\n\\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders while contributing technical expertise and event coordination.\\n\\n## Key Contributions\\n\\n### Website & Online Presence\\n- Built https://ccsf-cs.club using Astro framework\\n- Achieved #1 Google ranking for \\"CS club\\" searches in San Francisco region\\n- Created resource hub for students learning modern web development\\n- Introduced students to Astro, helping them build professional portfolios\\n\\n### Event Leadership\\n- Led student teams attending 100+ tech events across the Bay Area\\n- Organized group attendance at hackathons, workshops, and tech meetups\\n- Connected students with SF tech community opportunities\\n- Mentored first-time hackathon participants\\n\\n### Administrative Support\\n- Managed club finances as treasurer\\n- Provided guidance while empowering younger students to take leadership roles\\n- Supported student-led initiatives with financial and technical expertise\\n\\n## Impact\\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\\n- **Community Growth**: Helped build thriving community connecting CCSF students to tech careers\\n- **Technical Education**: Created pathways for non-traditional students into tech through accessible resources and mentorship\\n\\n*2023-present*","technologies":["Astro","Community Building","Education","Event Management"],"featured":true,"order":1,"team":null,"live_url":"https://ccsf-cs.club","case_study_url":null,"category":"education"}	{"role":"Officer"}	\N	\N
162	194	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T07:23:28.297Z","title":"The Velocity Shift: What These Architectural Choices Actually Delivered","published":true,"content":"# The Velocity Shift: What These Architectural Choices Actually Delivered\\n\\nTen hours to production. But more importantly: a site that's fast to load, fast to update, and fast to extend. Here's what each choice got me.\\n\\n## The Stack in Practice\\n\\n**Frontend:** Astro (SSR)\\n**API:** Hono (Node.js)\\n**CMS:** Directus\\n**Database:** PostgreSQL\\n**Infrastructure:** Docker Compose\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n"}	{"title":"The Velocity Shift: What These Architectural Choices Actually Delivered","content":"# The Velocity Shift: What These Architectural Choices Actually Delivered\\n\\nTen hours to production. But more importantly: a site that's fast to load, fast to update, and fast to extend. Here's what each choice got me.\\n\\n## The Stack in Practice\\n\\n**Frontend:** Astro (SSR)\\n**API:** Hono (Node.js)\\n**CMS:** Directus\\n**Database:** PostgreSQL\\n**Infrastructure:** Docker Compose\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n","date_updated":"2025-10-14T07:23:28.297Z"}	\N	\N
163	195	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T07:25:06.494Z","title":"LLM-Driven Portfolio My Way","published":true,"content":"Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there.\\n\\n## The Stack in Practice\\n\\n**Frontend:** Astro (SSR)\\n**API:** Hono (Node.js)\\n**CMS:** Directus\\n**Database:** PostgreSQL\\n**Infrastructure:** Docker Compose\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n"}	{"title":"LLM-Driven Portfolio My Way","content":"Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there.\\n\\n## The Stack in Practice\\n\\n**Frontend:** Astro (SSR)\\n**API:** Hono (Node.js)\\n**CMS:** Directus\\n**Database:** PostgreSQL\\n**Infrastructure:** Docker Compose\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n","date_updated":"2025-10-14T07:25:06.494Z"}	\N	\N
164	196	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T07:25:26.475Z","title":"Vibe Coding a Portfolio My Way","published":true,"content":"Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there.\\n\\n## The Stack in Practice\\n\\n**Frontend:** Astro (SSR)\\n**API:** Hono (Node.js)\\n**CMS:** Directus\\n**Database:** PostgreSQL\\n**Infrastructure:** Docker Compose\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n"}	{"title":"Vibe Coding a Portfolio My Way","date_updated":"2025-10-14T07:25:26.475Z"}	\N	\N
165	197	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T07:26:17.962Z","title":"Vibe Coding a Portfolio My Way","published":true,"content":"Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there, and what it uses.\\n\\n## The Stack in Practice\\n\\n**Frontend:** Astro (SSR)\\n**API:** Hono (Node.js)\\n**CMS:** Directus\\n**Database:** PostgreSQL\\n**Infrastructure:** Docker Compose\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n"}	{"content":"Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there, and what it uses.\\n\\n## The Stack in Practice\\n\\n**Frontend:** Astro (SSR)\\n**API:** Hono (Node.js)\\n**CMS:** Directus\\n**Database:** PostgreSQL\\n**Infrastructure:** Docker Compose\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n","date_updated":"2025-10-14T07:26:17.962Z"}	\N	\N
166	198	posts	7	{"id":7,"date_created":"2025-10-14T05:17:37.327Z","date_updated":"2025-10-14T07:26:45.088Z","title":"Vibe Coding a Portfolio My Way","published":true,"content":"Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there, and what it uses.\\n\\nThe Stack in Practice:\\n\\n**Frontend:** Astro (SSR)\\n\\n**API:** Hono (Node.js)\\n\\n**CMS:** Directus\\n\\n**Database:** PostgreSQL\\n\\n**Infrastructure:** Docker Compose\\n\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n"}	{"content":"Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there, and what it uses.\\n\\nThe Stack in Practice:\\n\\n**Frontend:** Astro (SSR)\\n\\n**API:** Hono (Node.js)\\n\\n**CMS:** Directus\\n\\n**Database:** PostgreSQL\\n\\n**Infrastructure:** Docker Compose\\n\\n**Deployment:** Cloudflare Tunnels\\n\\nNot arbitrary. Each choice paid dividends.\\n\\n## What Astro Actually Delivered\\n\\n### Shipped: 12KB JavaScript (total)\\n\\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\\n\\nAstro conversion: 12KB total. Most pages are pure HTML.\\n\\n**What this means:**\\n- First Contentful Paint: <0.8s\\n- Time to Interactive: <1.2s\\n- Lighthouse score: 97\\n\\n**The trade:** Lost React interactivity. Gained speed.\\n\\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\\n\\n### Build Time: 8 Seconds\\n\\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\\n\\nAstro: 8 second full build. Changes: instant.\\n\\n**What this means during development:**\\n- Change a component → See it immediately\\n- No waiting for webpack rebuilds\\n- Tight feedback loop = faster iteration\\n\\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\\n\\n### Content Routes: Zero Configuration\\n\\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\\n\\n**Next.js approach:**\\n- Set up dynamic routes\\n- Configure getStaticPaths\\n- Handle ISR if you want updates\\n- Deploy to regenerate\\n\\n**Astro approach:**\\n```astro\\n// pages/blog/[slug].astro\\nconst { slug } = Astro.params\\nconst post = await getBlogPost(slug)\\n```\\n\\nThat's it. SSR by default. No build required for content updates.\\n\\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\\n\\n## What Directus Actually Delivered\\n\\n### Non-Developer Content Updates\\n\\nMy partner can now:\\n- Add a new work project (no code)\\n- Update project descriptions (no code)\\n- Reorder featured projects (drag and drop)\\n- Fix typos in my bio (instant)\\n\\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\\n\\n**Now:** Every change = edit in Directus UI → save → instant.\\n\\n**The unlock:** I'm not the bottleneck anymore.\\n\\n### Real Relational Data\\n\\nWork projects have:\\n- Technologies (many-to-many)\\n- Categories (employment, hackathon, research)\\n- Status (published, draft, archived)\\n\\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\\n\\n**What this means:** Filtering \\"show me all hackathon projects using TypeScript\\" is a UI dropdown, not a query I need to write.\\n\\n### TypeScript SDK Out of the Box\\n\\n```typescript\\nimport { createDirectus, rest, readItems } from '@directus/sdk'\\n\\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\\n\\n// Fully typed\\nconst projects = await directus.request(\\n  readItems('work_projects', {\\n    filter: { status: { _eq: 'published' } },\\n    sort: ['order']\\n  })\\n)\\n```\\n\\n**What this delivered:**\\n- Autocomplete for all fields\\n- Type errors if I misspell a field name\\n- Build fails before runtime errors\\n\\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\\n\\n## What Hono Actually Delivered\\n\\n### 200KB → 12KB API Layer\\n\\nExpress is 200KB+. Hono is 12KB.\\n\\n**Does it matter?** For cold starts: yes.\\n\\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\\n\\n### Type-Safe Routing\\n\\n```typescript\\n// api/src/index.ts\\napp.get('/api/work-projects/:slug', async (c) => {\\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\\n  const project = await getWorkProject(slug)\\n  return c.json({ data: project })  // TypeScript validates the response\\n})\\n```\\n\\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\\n\\n**What this delivered:** Zero \\"undefined is not a function\\" errors. The API layer just works.\\n\\n### Edge-Ready (Future Proof)\\n\\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\\n\\n**Express:** Tied to Node.js.\\n\\n**Hono:** Platform-agnostic.\\n\\n**The bet:** Web runtimes are converging. Hono works everywhere.\\n\\n## What Docker Compose Actually Delivered\\n\\n### Identical Dev/Prod\\n\\nMy laptop: `docker compose up`\\nMy homelab server: `docker compose up`\\n\\nSame configs. Same behavior. No surprises.\\n\\n**What this prevented:**\\n- \\"Works on my machine\\" → It works everywhere\\n- Environment variable mismatches → All in `.env`\\n- Service startup races → Healthchecks enforce order\\n\\n**The save:** Zero deployment debugging. If it works locally, it works in production.\\n\\n### One Command Setup\\n\\nNew machine? Clone repo. Run:\\n\\n```bash\\ndocker compose up\\n```\\n\\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\\n\\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\\n\\n**With Docker:** One command.\\n\\n**Time saved:** 2 hours of setup → 2 minutes.\\n\\n## What Cloudflare Tunnels Actually Delivered\\n\\n### Zero Network Configuration\\n\\n**Traditional self-hosting requirements:**\\n- Port forwarding on router\\n- Dynamic DNS for changing IP\\n- SSL certificate management\\n- Firewall rules\\n- DDoS protection (hope for the best)\\n\\n**Cloudflare Tunnel:**\\n```bash\\ncloudflared tunnel --url http://localhost:4321\\n```\\n\\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\\n\\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\\n\\n### Free HTTPS\\n\\nLet's Encrypt works, but you need to:\\n- Run certbot\\n- Configure renewal\\n- Handle challenges\\n- Set up nginx/caddy\\n- Debug when it breaks\\n\\nCloudflare Tunnel: HTTPS by default. Zero configuration.\\n\\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\\n\\n## The Performance Reality\\n\\n### Lighthouse Scores\\n\\n- **Performance:** 97\\n- **Accessibility:** 100\\n- **Best Practices:** 100\\n- **SEO:** 100\\n\\n**What got us here:**\\n- Astro's minimal JavaScript\\n- Optimized image loading\\n- Server-side rendering\\n- Clean HTML structure\\n\\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\\n\\n### Real User Metrics\\n\\n**First Contentful Paint:** 0.6-0.8s\\n**Time to Interactive:** 1.0-1.2s\\n**Largest Contentful Paint:** 1.1s\\n\\n**For comparison:**\\n- Average Next.js site: 2-3s FCP\\n- Average portfolio site: 3-4s FCP\\n\\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\\n\\n### Backend Response Times\\n\\n**API response times (p95):**\\n- `/api/posts`: 45ms\\n- `/api/work-projects`: 38ms\\n- `/api/profile`: 22ms\\n\\n**Why fast:**\\n- Hono is lightweight\\n- PostgreSQL is local (same Docker network)\\n- No ORM overhead (direct Directus SDK)\\n\\n## The Developer Experience\\n\\n### Hot Reload: Actually Hot\\n\\nChange a component → See it in <100ms\\n\\n**Why:**\\n- Astro's fast refresh\\n- Docker volume mounts (no rebuild needed)\\n- Minimal build pipeline\\n\\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\\n\\n### Type Safety Across Boundaries\\n\\n```typescript\\n// Directus schema\\ninterface WorkProject { title: string }\\n\\n// API layer mirrors it\\ninterface WorkProject { title: string }\\n\\n// Frontend mirrors it\\ninterface WorkProject { title: string }\\n```\\n\\nMisspell `title` anywhere → Build fails.\\n\\n**What this prevented:** 5-6 bugs that would have been \\"why is this undefined?\\" in production.\\n\\n### Error Messages That Actually Help\\n\\n**Docker error:**\\n```\\nnetwork homelab-network declared as external, but could not be found\\n```\\n\\n**Fix:** `docker network create homelab-network`\\n\\n**Directus error:**\\n```\\nField \\"slug\\" is required but not provided\\n```\\n\\n**Fix:** Add `slug` to the request.\\n\\n**Why this matters:** Debugging is fast when errors are clear.\\n\\n## What This Enables\\n\\n### Content Updates Without Deployment\\n\\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\\n\\nNow: Edit in Directus → Save → Instant\\n\\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\\n\\n### Easy to Extend\\n\\nWant to add a \\"talks\\" section?\\n\\n1. Create `talks` collection in Directus (5 minutes)\\n2. Add API endpoint in Hono (2 lines)\\n3. Create Astro page (copy/paste work page pattern)\\n4. Done\\n\\n**Time:** 15 minutes. No refactoring. No breaking changes.\\n\\n### Self-Hosting Without Pain\\n\\nThis runs in my closet on a Debian server.\\n\\n**Costs:**\\n- Hardware: $200 one-time (mini PC)\\n- Electricity: ~$3/month\\n- Cloudflare Tunnel: Free\\n\\n**vs Vercel/Netlify:**\\n- Free tier limits: 100GB bandwidth, then $20/100GB\\n- Pro tier: $20/month minimum\\n\\n**Break-even:** After 3 months, self-hosting is cheaper.\\n\\n## The Honest Trade-offs\\n\\n### What I Lost\\n\\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\\n\\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\\n\\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\\n\\n### What I Gained\\n\\n**Speed:** 97 Lighthouse score. <1s interactive.\\n\\n**Control:** My data, my server, my rules.\\n\\n**Cost:** $3/month electricity vs $20/month hosting.\\n\\n**Flexibility:** Can run anything on this server, not just web apps.\\n\\n## The Results\\n\\n**Live:** https://b28.dev\\n\\n**Performance:**\\n- Lighthouse: 97\\n- FCP: <0.8s\\n- TTI: <1.2s\\n\\n**DX:**\\n- Hot reload: <100ms\\n- Type-safe: Build fails on errors\\n- One-command setup: `docker compose up`\\n\\n**Maintainability:**\\n- Content updates: 10 seconds\\n- Add new sections: 15 minutes\\n- Deploy changes: `git pull && docker compose up -d`\\n\\n**Cost:**\\n- Development: 10 hours active work\\n- Hosting: $3/month electricity\\n- Maintenance: ~1 hour/month\\n\\n## The Takeaway\\n\\nThese weren't random choices. Each tool delivered specific value:\\n\\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\\n- **Directus:** Non-developer updates\\n- **Hono:** Type-safe API, edge-ready\\n- **Docker:** Identical dev/prod\\n- **Cloudflare Tunnels:** Zero-config HTTPS\\n\\n**The pattern:** Choose tools for what they deliver, not what's popular.\\n\\n---\\n\\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\\n\\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\\n","date_updated":"2025-10-14T07:26:45.088Z"}	\N	\N
\.


--
-- Data for Name: directus_roles; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_roles (id, name, icon, description, parent) FROM stdin;
dd3993a4-6217-4159-a014-9fae656d0032	Administrator	verified	$t:admin_description	\N
\.


--
-- Data for Name: directus_sessions; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_sessions (token, "user", expires, ip, user_agent, share, origin, next_token) FROM stdin;
b661nroAKosezRomZyZkF038B3Mx5bMNe9j1LXUxaWZV2_PQ-FW0b27X2XkAE2Zq	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 04:50:55.957+00	172.18.1.1	curl/7.88.1	\N	\N	\N
U9eaxgunfjZ1jmdgNHpmM5OJsc4wquhfJBcyQRLWRrQADtDCsNyO4-mpp-jY1fMW	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 04:58:55.162+00	172.18.1.1	curl/7.88.1	\N	\N	\N
FPq8UyzJeoa9HBK4BSXliQlFOztOEEyiqW9PxAcgAHHhjqEd9890amOSr44R58WW	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:02:07.274+00	172.18.1.1	curl/7.88.1	\N	\N	\N
PIJCUEpjEUQLmlxHmU5O2ZR9EPHpFcCijCR3LAWaM8kWAQj4QsBDmSNRPV6OWcfo	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:05:55.434+00	172.18.1.1	curl/7.88.1	\N	\N	\N
fPsmzTHBeWqX29849X-3Fob6G3FHY0QZDjoUaXIGHguVBoE093I8bPJNbYur7SBC	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:07:15.399+00	172.18.1.1	curl/7.88.1	\N	\N	\N
GocSPwS1Uy5danbWEdrYD3pBSnMaWPk7xAid4mFFgqS4PSly_O6xGJg3BJescy1J	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:11:02.105+00	172.18.1.1	curl/7.88.1	\N	\N	\N
Lcm8UgYla_U3b1i1L178b7WdWUi9oUtqGEUzb2EARixVuetHGmnKFQr9_anZdAKM	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 04:21:19.815+00	172.18.1.1	curl/7.88.1	\N	\N	\N
Gg-3AvaHotMhraoUHw1bvgJnnoBzxHDAl_otYw6V953Qf9PZapI-f552WMdEr15n	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:15:04.044+00	172.18.1.1	curl/7.88.1	\N	\N	\N
jXZFLBu-3DDVXS2GKJuxPnq2OAA_hWT7hEz37uTEj0ZvJK2qsdZaZUR1-N19jIJt	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:15:32.402+00	172.18.1.1	curl/7.88.1	\N	\N	\N
9wluqzkArzR7zSifhERqsdcrZj8Ozxj1k7apFwsUc-iASfWdlLxarFTgmHuQ4mQU	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:17:18.747+00	172.18.1.1	curl/7.88.1	\N	\N	\N
gWbug57B4yQVJ7VQFrg__dofRxlyyRt9PtdwtI33wWbs6CoIMjfBHBn3SB__knXK	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 05:17:36.832+00	172.18.1.1	curl/7.88.1	\N	\N	\N
T4U6FK8pxnjlXR75RjE4ixT_FyfWZSgZ9mlH1OdIdbpt5JpUbjtyR6fq_N4wPoJ3	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 04:30:43.338+00	172.18.1.1	curl/7.88.1	\N	\N	\N
2P7H4bv22Z5t-pE4VaGAgzQYjA5XHofKAXEEtTsXYqj3lm1qBwe8S_hJMETpGRaw	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 06:48:12.273+00	172.18.1.1	curl/7.88.1	\N	\N	\N
4LM-9RSI1jtvnu_ZmwcS2o1QK4tDs2T1YAoM-JRgIg2FCdUesU_F7HcF5AXqcsdp	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 04:37:38.989+00	172.18.1.1	curl/7.88.1	\N	\N	\N
bhSB-1qBr6SpCpHluFkfooFOtvExQ-QscXtPMhJObyJmQeXEV-QQYtPbAevQ32xf	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 04:38:33.947+00	172.18.1.1	curl/7.88.1	\N	\N	\N
CkkxwtXVGbrxx_-dPAHDy10n5MHIhFMBe0hD6XJf3xdsFWb2Y7uMKRMOs1DgtkFX	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 06:56:49.183+00	172.18.1.1	curl/7.88.1	\N	\N	\N
ZnydABCgGOhHqxi_CezSDuQAtBK3tb0KYXyjnndjFBUvwhwDKAlRB99_-jqrAcwf	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-15 06:25:43.06+00	172.18.1.1	Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/141.0.0.0 Safari/537.36	\N	http://directus.homelab.local	\N
EQppT3w9ChBal-dcCM26rNN7ngzFapDV_uwfvrCf2UQWNCCgQDY-ZaQiN5pZDt_l	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 06:57:03.201+00	172.18.1.1	curl/7.88.1	\N	\N	\N
IMbaQknTmxTQmvREIH2_e3l_JtPWvt4AJ_lbnuV5O5aSYOSn7b98Fc9tT-XyC0Sl	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 06:26:58.098+00	172.18.1.1	curl/7.88.1	\N	\N	\N
UmZZcZMAnkOt3lWIPJVPPLmtLoMxss_0ILPMIF5PEZJRQsSV71O7dk3IIoBy4_mS	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 06:57:15.52+00	172.18.1.1	curl/7.88.1	\N	\N	\N
klVbqTHRSTTMYFoYuvL6knVVvTskcrYRlmDPmrQBU43L32liaytTZ5M__qDY8PhC	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 06:58:50.047+00	172.18.1.1	curl/7.88.1	\N	\N	\N
DVHiD-_lYbh09euDuhKUY7XqU3nlGZuXAk7W-Ftuj8gJVIBryCGfiNI1VI4j-Tf6	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-21 07:23:27.653+00	172.18.1.1	curl/7.88.1	\N	\N	\N
5FvksvtTcs5Z-UQ4FL97bTKTorcgEUzQosQk0MPipmXlIKYtwpMfZhzc9mcOPMsQ	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:23:49.802+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	\N	http://directus.homelab.local	v9ohgN_ITIKiEhcOKa2xUTOp_vcpJp-Wp1Qe8VNmNr25niXnJuDfAilypZ_14R-q
v9ohgN_ITIKiEhcOKa2xUTOp_vcpJp-Wp1Qe8VNmNr25niXnJuDfAilypZ_14R-q	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-14 07:23:52.223+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	\N	http://directus.homelab.local	7wmySLeR--uU2xMVMPaLy3j5xOHQ4OFXTzbpyfCyRiIlLtayAjlV_jN6Oom9GWzN
7wmySLeR--uU2xMVMPaLy3j5xOHQ4OFXTzbpyfCyRiIlLtayAjlV_jN6Oom9GWzN	446b0591-88bd-4122-8877-6ff5b00e4201	2025-10-15 07:23:42.223+00	100.114.95.71	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:143.0) Gecko/20100101 Firefox/143.0	\N	http://directus.homelab.local	\N
\.


--
-- Data for Name: directus_settings; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_settings (id, project_name, project_url, project_color, project_logo, public_foreground, public_background, public_note, auth_login_attempts, auth_password_policy, storage_asset_transform, storage_asset_presets, custom_css, storage_default_folder, basemaps, mapbox_key, module_bar, project_descriptor, default_language, custom_aspect_ratios, public_favicon, default_appearance, default_theme_light, theme_light_overrides, default_theme_dark, theme_dark_overrides, report_error_url, report_bug_url, report_feature_url, public_registration, public_registration_verify_email, public_registration_role, public_registration_email_filter, visual_editor_urls, accepted_terms, project_id, mcp_enabled, mcp_allow_deletes, mcp_prompts_collection, mcp_system_prompt_enabled, mcp_system_prompt) FROM stdin;
1	Directus	\N	#6644FF	\N	\N	\N	\N	25	\N	all	\N	\N	\N	\N	\N	\N	\N	en-US	\N	\N	auto	\N	\N	\N	\N	\N	\N	\N	f	t	\N	\N	\N	t	0199e02f-e4a9-7130-9a23-b23adc90f974	f	f	\N	t	\N
\.


--
-- Data for Name: directus_shares; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_shares (id, name, collection, item, role, password, user_created, date_created, date_start, date_end, times_used, max_uses) FROM stdin;
\.


--
-- Data for Name: directus_translations; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_translations (id, language, key, value) FROM stdin;
\.


--
-- Data for Name: directus_users; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_users (id, first_name, last_name, email, password, location, title, description, tags, avatar, language, tfa_secret, status, role, token, last_access, last_page, provider, external_identifier, auth_data, email_notifications, appearance, theme_dark, theme_light, theme_light_overrides, theme_dark_overrides, text_direction) FROM stdin;
446b0591-88bd-4122-8877-6ff5b00e4201	Admin	User	john.hk.chen@gmail.com	$argon2id$v=19$m=65536,t=3,p=4$70RGZdTBnbCm0CTQ8HOLWw$xun4iG0hRBHuF/BsICZH0K9V/uk68+kk/Tgrrx6MWGM	\N	\N	\N	\N	\N	\N	\N	active	dd3993a4-6217-4159-a014-9fae656d0032	\N	2025-10-14 07:23:42.229+00	/content/posts	default	\N	\N	t	\N	\N	\N	\N	\N	auto
\.


--
-- Data for Name: directus_versions; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_versions (id, key, name, collection, item, hash, date_created, date_updated, user_created, user_updated, delta) FROM stdin;
\.


--
-- Data for Name: directus_webhooks; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.directus_webhooks (id, name, method, url, status, data, actions, collections, headers, was_active_before_deprecation, migrated_flow) FROM stdin;
\.


--
-- Data for Name: posts; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.posts (id, date_created, date_updated, title, published, content) FROM stdin;
8	2025-10-14 06:27:10.44+00	2025-10-14 06:50:48.649+00	v0 to Production	t	One day of prompting for a production-ready portfolio. I knew exactly what to ask for.\n\n## The Setup\n\n**What I saw:** v0.dev templates at an AWS event locked to Vercel's framework.\n\n**What I knew:** Astro exists. Directus exists. Hono exists. I'd learned them through tech events, forum diving, building small experiments.\n\n**What happened:** Sonnet 4.5 drops. One day of focused prompting. Working Astro variant with Directus CMS. Production-deployed.\n\n**Why it worked:** Curation and taste. Not because AI figured it out.\n\n## What AI Gives You Without Direction\n\nLeft to its own devices, Claude Code suggests:\n\n**The default stack:**\n- Express (because it's popular)\n- Basic JavaScript (because it's simple)\n- Hardcoded data (because it works)\n- Generic placeholders everywhere\n\n**What you get:** Something that runs. Nothing you'd ship.\n\nThis is the trap: AI coding tools *work*, but they optimize for "runs quickly" not "production-grade."\n\n## What Changes with Curation\n\nWhen you know what exists, you can prompt differently.\n\n**Without curation:**\n> "Build me a portfolio site"\n\nResult: Next.js with hardcoded content. Generic. Forgettable.\n\n**With curation:**\n> "I have a v0.dev template. Convert it to Astro. Use Directus for content management. Lightweight API layer between them. Type-safe."\n\nResult: Production architecture in a day.\n\n**The difference:** I knew Astro, Directus, and Hono existed. I'd seen them at events, experimented with them in small projects, understood their trade-offs.\n\n## Where I Actually Learned\n\n### Tech Events\n\nSeeing Vercel demo v0.dev at AWS. Watching the framework lock-in. Thinking: "Great UI, wrong stack for my needs."\n\nHallway conversations about Directus. Someone mentioning Hono's edge-ready architecture. Filing it away.\n\n### The Internet Annals\n\nForum threads about Astro vs Next.js for content sites. Blog posts comparing headless CMS options. GitHub issues showing real integration patterns.\n\nNot tutorials. Real people discussing real trade-offs.\n\n### Small Experiments with Claude Code\n\nBuilding throwaway projects:\n- "Show me how Directus works"\n- "What's the Hono API surface look like?"\n- "How does Astro handle dynamic routes?"\n\nRudimentary understanding. Just enough to know what's possible.\n\n## The Moment of Synthesis\n\nv0.dev templates are beautiful. But I wanted:\n- Astro (better for content than Next.js)\n- Self-hosted (not Vercel-locked)\n- Directus (better admin UI than competitors)\n- Hono (lighter than Express)\n\n**The key:** I could name these choices. Claude Code didn't suggest them. I directed it toward them.\n\n## What One Day of Prompting Looks Like\n\n### Morning: The Conversion\n\n**Me:** "This v0.dev template is Next.js. Convert the component structure to Astro. Keep the design, swap the framework."\n\n**Claude Code:** Converts components. Shows me incompatibilities. We iterate.\n\n**The difference from generic:** I knew to ask for Astro specifically. I knew what I was trading (React interactivity for static speed).\n\n### Afternoon: The Integration\n\n**Me:** "Now integrate Directus. I need a content adapter pattern—Astro expects content collections, Directus is an API."\n\n**Claude Code:** Implements the adapter. Type-safe throughout.\n\n**Why this worked:** I knew the pattern name. I'd seen it discussed in Astro forums. Claude Code filled in syntax, but I directed architecture.\n\n### Evening: The Deployment\n\n**Me:** "Docker Compose. Frontend, API, Directus. Healthchecks so they start in order."\n\n**Claude Code:** Generates docker-compose.yml. We debug networking.\n\n**The curation:** I knew Docker Compose (not Kubernetes) because I'd learned the trade-offs at tech events. Claude Code wrote the config, but I chose the tool.\n\n## The LLM-Driven Issue Loop\n\nThis is where Sonnet 4.5 shines:\n\n**Pattern:**\n1. Build a feature\n2. Test it\n3. Hit an error\n4. Paste error to Claude Code\n5. It suggests fix\n6. Repeat\n\n**Example:**\n- Docker services can't reach each other\n- Paste error logs\n- "Add them all to the same network"\n- Works\n\n**Why this is different:** Earlier models would explain Docker networking. Sonnet 4.5 just fixes it. One-shot solutions instead of educational detours.\n\nBut here's the key: **I knew enough to recognize good solutions.** When it suggested healthchecks, I understood why. When it chose Traefik labels, I knew what they did.\n\nCuration isn't just *choosing* tools. It's *evaluating* AI suggestions.\n\n## What Curation Actually Means\n\n### 1. Knowing What Exists\n\nI can't ask for Hono if I don't know it exists. I learned it from:\n- Tech event hallway conversation\n- Seeing it on a "lightweight Node frameworks" list\n- Building a throwaway API to understand it\n\n**The work:** Self-directed learning. Tech events. Experimentation.\n\n### 2. Understanding Trade-offs\n\nWhen Claude Code suggests Express, I know to push back: "What about Hono?"\n\nWhen it suggests Strapi, I counter with: "Directus has a better admin UI."\n\n**The knowledge:** Not from AI. From forums, GitHub issues, comparing tools myself.\n\n### 3. Recognizing Good Architecture\n\nClaude Code suggests the content adapter pattern. I recognize it's solid because:\n- Separates concerns\n- Keeps Astro pages clean\n- Makes CMS swappable\n\n**The judgment:** Built from seeing patterns in real codebases, not from AI explanations.\n\n### 4. Directing, Not Just Accepting\n\nDefault: "Build me X" → AI chooses everything\n\nCurated: "I want A, B, C integrated. Show me how" → You choose, AI implements\n\n**The difference:** Agency. You're in control.\n\n## Why This Moment Matters\n\n### The Timing\n\n**Anthropic bets big on coding AI:** Sonnet 4.5 is noticeably better at multi-file edits, integration patterns, configuration generation.\n\n**Production-grade tools mature:** Directus, Hono, Astro are all stable. Not experimental.\n\n**v0.dev shows the demand:** People want beautiful templates. They just don't want framework lock-in.\n\n**Confluence:** I have the curation. AI has the capability. Tools are production-ready.\n\n### What Makes This Reproducible\n\nNot "use these exact tools."\n\nBut: **Build your curation muscle, then execute with AI.**\n\n**How to build curation:**\n1. Go to tech events (see tools demoed, hear hallway chatter)\n2. Dig through forums (understand why people choose X over Y)\n3. Build small experiments (gain rudimentary understanding)\n4. Develop taste (know when "good enough" vs "production-grade")\n\n**Then when Sonnet 4.5 (or better) exists:**\n- You can name what you want\n- AI handles implementation details\n- One day of focused work = production site\n\n## The Honest Comparison\n\n### Without Curation\n**Prompt:** "Build me a portfolio site"\n\n**Result:** Express + basic JS + placeholders\n\n**Time to production:** Weeks of refactoring to make it real\n\n### With Curation\n**Prompt:** "Convert this v0.dev template to Astro. Integrate Directus. Use Hono for API. Docker Compose deployment."\n\n**Result:** Production-grade architecture from day one\n\n**Time to production:** One day of focused prompting\n\n**The difference:** I did the learning beforehand. AI does the implementation now.\n\n## What You Actually Need to Learn\n\n**Not from AI:**\n- What tools exist in the ecosystem\n- Why people choose specific tools\n- Trade-offs between options\n- What "production-grade" looks like\n\n**From AI:**\n- How to integrate specific tools\n- Configuration syntax\n- Implementation patterns\n- Fixing specific errors\n\n**The split:** Strategic knowledge is yours. Tactical execution is AI's.\n\n## The Pattern\n\n**Phase 1: Self-Directed Learning**\n- Attend tech events\n- Read forums and GitHub issues\n- Experiment with tools in isolation\n- Develop opinions about trade-offs\n\n**Phase 2: Small Experiments**\n- Build throwaway projects with Claude Code\n- Gain rudimentary understanding\n- Learn what's possible, what's hard\n\n**Phase 3: Recognition**\n- "I know what I want to build"\n- "I know which tools fit together"\n- "I can direct an AI toward this vision"\n\n**Phase 4: Execution**\n- One day of focused prompting\n- LLM-driven issue loop (error → fix → repeat)\n- Production-grade result\n\n## The Result\n\n**Live:** https://b28.dev\n\n**Timeline:**\n- Months of learning (events, experiments, forums)\n- One day of building (prompting + iteration)\n\n**Stack:** Astro, Hono, Directus, PostgreSQL, Docker, Cloudflare Tunnels\n\n**Why these choices:** Not AI suggestions. My curation from tech events and self-directed learning.\n\n**Why one day:** Because Sonnet 4.5 is good at implementation when you direct it well.\n\n## The Real Unlock\n\n**2023:** You needed to know how to build it yourself. AI helped with boilerplate.\n\n**2025:** You need to know what to build and why. AI builds it for you.\n\n**The skill that matters:** Curation. Knowing what exists, what fits together, what's production-grade.\n\n**How you build that skill:** Tech events. Forum diving. Small experiments. Developing taste.\n\n**When AI amplifies it:** When you can say "I want A, B, C integrated" and the AI handles implementation.\n\nThe tools haven't changed. The leverage has.\n\n---\n\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\n\n**Real methodology:** Curated architecture + AI implementation = one-day production deploy\n
7	2025-10-14 05:17:37.327+00	2025-10-14 07:26:45.088+00	Vibe Coding a Portfolio My Way	t	Ten hours from start to production. A site that's fast to load, fast to update, and fast to extend. Here's how I got there, and what it uses.\n\nThe Stack in Practice:\n\n**Frontend:** Astro (SSR)\n\n**API:** Hono (Node.js)\n\n**CMS:** Directus\n\n**Database:** PostgreSQL\n\n**Infrastructure:** Docker Compose\n\n**Deployment:** Cloudflare Tunnels\n\nNot arbitrary. Each choice paid dividends.\n\n## What Astro Actually Delivered\n\n### Shipped: 12KB JavaScript (total)\n\nv0.dev's Next.js template: ~200KB JavaScript minimum. Just for the framework.\n\nAstro conversion: 12KB total. Most pages are pure HTML.\n\n**What this means:**\n- First Contentful Paint: <0.8s\n- Time to Interactive: <1.2s\n- Lighthouse score: 97\n\n**The trade:** Lost React interactivity. Gained speed.\n\n**Was it worth it?** For a portfolio? Absolutely. I don't need client-side state management for showing projects.\n\n### Build Time: 8 Seconds\n\nNext.js dev server startup: 15-20 seconds. Every change: 2-3 seconds hot reload.\n\nAstro: 8 second full build. Changes: instant.\n\n**What this means during development:**\n- Change a component → See it immediately\n- No waiting for webpack rebuilds\n- Tight feedback loop = faster iteration\n\n**The multiplier:** 20 small changes in 10 minutes vs 20 small changes in 30 minutes.\n\n### Content Routes: Zero Configuration\n\nNeeded routes for `/blog/[slug]` and `/work/[slug]`.\n\n**Next.js approach:**\n- Set up dynamic routes\n- Configure getStaticPaths\n- Handle ISR if you want updates\n- Deploy to regenerate\n\n**Astro approach:**\n```astro\n// pages/blog/[slug].astro\nconst { slug } = Astro.params\nconst post = await getBlogPost(slug)\n```\n\nThat's it. SSR by default. No build required for content updates.\n\n**What this delivered:** Update a post in Directus → Refresh → See it. No deployment.\n\n## What Directus Actually Delivered\n\n### Non-Developer Content Updates\n\nMy partner can now:\n- Add a new work project (no code)\n- Update project descriptions (no code)\n- Reorder featured projects (drag and drop)\n- Fix typos in my bio (instant)\n\n**Before (hardcoded content):** Every change = text me → I edit code → commit → deploy → 10 minutes.\n\n**Now:** Every change = edit in Directus UI → save → instant.\n\n**The unlock:** I'm not the bottleneck anymore.\n\n### Real Relational Data\n\nWork projects have:\n- Technologies (many-to-many)\n- Categories (employment, hackathon, research)\n- Status (published, draft, archived)\n\n**Strapi/Payload:** Would work, but Directus's relational UI is better.\n\n**What this means:** Filtering "show me all hackathon projects using TypeScript" is a UI dropdown, not a query I need to write.\n\n### TypeScript SDK Out of the Box\n\n```typescript\nimport { createDirectus, rest, readItems } from '@directus/sdk'\n\nconst directus = createDirectus<Schema>('http://directus:8055').with(rest())\n\n// Fully typed\nconst projects = await directus.request(\n  readItems('work_projects', {\n    filter: { status: { _eq: 'published' } },\n    sort: ['order']\n  })\n)\n```\n\n**What this delivered:**\n- Autocomplete for all fields\n- Type errors if I misspell a field name\n- Build fails before runtime errors\n\n**The save:** Caught 8 bugs during development that would have been runtime errors in production.\n\n## What Hono Actually Delivered\n\n### 200KB → 12KB API Layer\n\nExpress is 200KB+. Hono is 12KB.\n\n**Does it matter?** For cold starts: yes.\n\n**Reality check:** This API runs in Docker on my homelab. Cold starts aren't an issue. I chose Hono for DX, not bundle size.\n\n### Type-Safe Routing\n\n```typescript\n// api/src/index.ts\napp.get('/api/work-projects/:slug', async (c) => {\n  const slug = c.req.param('slug')  // TypeScript knows this is a string\n  const project = await getWorkProject(slug)\n  return c.json({ data: project })  // TypeScript validates the response\n})\n```\n\n**Express equivalent:** Type safety is manual. You add types yourself or use separate libraries.\n\n**What this delivered:** Zero "undefined is not a function" errors. The API layer just works.\n\n### Edge-Ready (Future Proof)\n\nI'm running this on Docker now. If I ever move to Cloudflare Workers or Deno Deploy, Hono already runs there.\n\n**Express:** Tied to Node.js.\n\n**Hono:** Platform-agnostic.\n\n**The bet:** Web runtimes are converging. Hono works everywhere.\n\n## What Docker Compose Actually Delivered\n\n### Identical Dev/Prod\n\nMy laptop: `docker compose up`\nMy homelab server: `docker compose up`\n\nSame configs. Same behavior. No surprises.\n\n**What this prevented:**\n- "Works on my machine" → It works everywhere\n- Environment variable mismatches → All in `.env`\n- Service startup races → Healthchecks enforce order\n\n**The save:** Zero deployment debugging. If it works locally, it works in production.\n\n### One Command Setup\n\nNew machine? Clone repo. Run:\n\n```bash\ndocker compose up\n```\n\nThat's it. Frontend, API, Directus, PostgreSQL all running. Connected. Networked. Ready.\n\n**Without Docker:** Install Node. Install PostgreSQL. Configure PostgreSQL. Set up networking. Configure environment variables. Debug why they can't talk to each other.\n\n**With Docker:** One command.\n\n**Time saved:** 2 hours of setup → 2 minutes.\n\n## What Cloudflare Tunnels Actually Delivered\n\n### Zero Network Configuration\n\n**Traditional self-hosting requirements:**\n- Port forwarding on router\n- Dynamic DNS for changing IP\n- SSL certificate management\n- Firewall rules\n- DDoS protection (hope for the best)\n\n**Cloudflare Tunnel:**\n```bash\ncloudflared tunnel --url http://localhost:4321\n```\n\nThat's it. HTTPS included. DDoS protection included. No exposed ports.\n\n**What this means:** I can self-host on residential internet without telling my ISP or configuring my router.\n\n### Free HTTPS\n\nLet's Encrypt works, but you need to:\n- Run certbot\n- Configure renewal\n- Handle challenges\n- Set up nginx/caddy\n- Debug when it breaks\n\nCloudflare Tunnel: HTTPS by default. Zero configuration.\n\n**Time saved:** 4 hours of SSL debugging → 0 minutes.\n\n## The Performance Reality\n\n### Lighthouse Scores\n\n- **Performance:** 97\n- **Accessibility:** 100\n- **Best Practices:** 100\n- **SEO:** 100\n\n**What got us here:**\n- Astro's minimal JavaScript\n- Optimized image loading\n- Server-side rendering\n- Clean HTML structure\n\n**The baseline:** v0.dev template scored 85-90. Conversion to Astro added 10 points.\n\n### Real User Metrics\n\n**First Contentful Paint:** 0.6-0.8s\n**Time to Interactive:** 1.0-1.2s\n**Largest Contentful Paint:** 1.1s\n\n**For comparison:**\n- Average Next.js site: 2-3s FCP\n- Average portfolio site: 3-4s FCP\n\n**Why:** No React hydration. No JavaScript bundles. Pure HTML until needed.\n\n### Backend Response Times\n\n**API response times (p95):**\n- `/api/posts`: 45ms\n- `/api/work-projects`: 38ms\n- `/api/profile`: 22ms\n\n**Why fast:**\n- Hono is lightweight\n- PostgreSQL is local (same Docker network)\n- No ORM overhead (direct Directus SDK)\n\n## The Developer Experience\n\n### Hot Reload: Actually Hot\n\nChange a component → See it in <100ms\n\n**Why:**\n- Astro's fast refresh\n- Docker volume mounts (no rebuild needed)\n- Minimal build pipeline\n\n**The difference:** Tight feedback loop. Iterate 10x in an hour, not a day.\n\n### Type Safety Across Boundaries\n\n```typescript\n// Directus schema\ninterface WorkProject { title: string }\n\n// API layer mirrors it\ninterface WorkProject { title: string }\n\n// Frontend mirrors it\ninterface WorkProject { title: string }\n```\n\nMisspell `title` anywhere → Build fails.\n\n**What this prevented:** 5-6 bugs that would have been "why is this undefined?" in production.\n\n### Error Messages That Actually Help\n\n**Docker error:**\n```\nnetwork homelab-network declared as external, but could not be found\n```\n\n**Fix:** `docker network create homelab-network`\n\n**Directus error:**\n```\nField "slug" is required but not provided\n```\n\n**Fix:** Add `slug` to the request.\n\n**Why this matters:** Debugging is fast when errors are clear.\n\n## What This Enables\n\n### Content Updates Without Deployment\n\nBefore: Edit markdown → Commit → Push → Build → Deploy → 5 minutes\n\nNow: Edit in Directus → Save → Instant\n\n**Real example:** Fixed a typo in my bio. Took 10 seconds. No deployment.\n\n### Easy to Extend\n\nWant to add a "talks" section?\n\n1. Create `talks` collection in Directus (5 minutes)\n2. Add API endpoint in Hono (2 lines)\n3. Create Astro page (copy/paste work page pattern)\n4. Done\n\n**Time:** 15 minutes. No refactoring. No breaking changes.\n\n### Self-Hosting Without Pain\n\nThis runs in my closet on a Debian server.\n\n**Costs:**\n- Hardware: $200 one-time (mini PC)\n- Electricity: ~$3/month\n- Cloudflare Tunnel: Free\n\n**vs Vercel/Netlify:**\n- Free tier limits: 100GB bandwidth, then $20/100GB\n- Pro tier: $20/month minimum\n\n**Break-even:** After 3 months, self-hosting is cheaper.\n\n## The Honest Trade-offs\n\n### What I Lost\n\n**React Interactivity:** Can't build complex SPAs. Fine for a portfolio.\n\n**Vercel Niceties:** No preview deploys. No automatic HTTPS per branch. But I didn't need them.\n\n**Managed Database:** I maintain PostgreSQL myself. But Docker makes it trivial.\n\n### What I Gained\n\n**Speed:** 97 Lighthouse score. <1s interactive.\n\n**Control:** My data, my server, my rules.\n\n**Cost:** $3/month electricity vs $20/month hosting.\n\n**Flexibility:** Can run anything on this server, not just web apps.\n\n## The Results\n\n**Live:** https://b28.dev\n\n**Performance:**\n- Lighthouse: 97\n- FCP: <0.8s\n- TTI: <1.2s\n\n**DX:**\n- Hot reload: <100ms\n- Type-safe: Build fails on errors\n- One-command setup: `docker compose up`\n\n**Maintainability:**\n- Content updates: 10 seconds\n- Add new sections: 15 minutes\n- Deploy changes: `git pull && docker compose up -d`\n\n**Cost:**\n- Development: 10 hours active work\n- Hosting: $3/month electricity\n- Maintenance: ~1 hour/month\n\n## The Takeaway\n\nThese weren't random choices. Each tool delivered specific value:\n\n- **Astro:** Speed (12KB JS, 97 Lighthouse)\n- **Directus:** Non-developer updates\n- **Hono:** Type-safe API, edge-ready\n- **Docker:** Identical dev/prod\n- **Cloudflare Tunnels:** Zero-config HTTPS\n\n**The pattern:** Choose tools for what they deliver, not what's popular.\n\n---\n\n**Template credit:** Felix Macaspac's v0.dev minimalist portfolio\n\n**The velocity shift:** Right tools → Fast site, fast updates, fast iteration\n
\.


--
-- Data for Name: profile; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.profile (id, full_name, first_name, last_name, title, description, email, location, portfolio_year, availability, availability_text, current_role_title, current_role_company, current_role_duration, work_section_title, work_section_date_range, connect_title, connect_description, footer_copyright, footer_attribution, footer_year) FROM stdin;
1	John Chen	John	Chen	Creative Software Engineer	Building AI-powered applications with LLMs and agentic systems. Full-stack engineer specializing in rapid prototyping and production ML integrations.	john.hk.chen@gmail.com	San Francisco, CA	2025	t	Open to work — AI/ML Engineer	Independent Software Engineer	Self-Employed	2020 — Present	Selected Work	2015 — Present	Let's Connect	Open for AI/ML roles, contract work, and technical consulting on LLM/agentic applications.	John Chen	Built with Astro, Hono, Directus & Claude. Design by v0 + Felix M.	2025
\.


--
-- Data for Name: skills; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.skills (id, name, category, proficiency, "order", featured) FROM stdin;
1	Claude	aiml	expert	1	t
3	LangChain	aiml	expert	3	t
4	BAML	aiml	intermediate	4	t
5	Weaviate	aiml	intermediate	5	t
7	CrewAI	aiml	intermediate	7	f
8	PyTorch	aiml	intermediate	8	f
9	HuggingFace	aiml	intermediate	9	f
10	Stable Diffusion	aiml	intermediate	10	f
11	Python	backend	expert	11	t
12	FastAPI	backend	expert	12	t
14	Rust	backend	intermediate	14	t
15	TypeScript	frontend	expert	15	t
16	React	frontend	expert	16	t
17	Astro	frontend	expert	17	t
19	Docker	devops	expert	19	t
20	flox	devops	intermediate	20	f
21	n8n	devops	intermediate	21	f
13	Node.js	backend	expert	13	f
6	LlamaIndex	aiml	intermediate	6	f
18	Tailwind CSS	frontend	expert	18	f
2	ChatGPT	aiml	expert	2	t
\.


--
-- Data for Name: social_links; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.social_links (id, name, handle, url, icon, "order", visible) FROM stdin;
1	GitHub	@johnhkchen	https://github.com/johnhkchen	github	1	t
2	LinkedIn	john-chen-364294101	https://www.linkedin.com/in/john-chen-364294101/	linkedin	2	t
3	Email	john.hk.chen@gmail.com	mailto:john.hk.chen@gmail.com	email	3	t
\.


--
-- Data for Name: work_projects; Type: TABLE DATA; Schema: public; Owner: homelab
--

COPY public.work_projects (id, status, title, slug, company, role, year, duration, description, content, technologies, featured, "order", team, live_url, case_study_url, category) FROM stdin;
4	published	SF Legacy Business Registry - Civic Tech	sf-legacy-business-registry	Hackathon Project	Full Stack Developer	2025	8 hours	Built PDF-to-structured-data pipeline using LlamaParse to transform San Francisco legacy business applications into an engaging, searchable database.	## Problem\n\nSan Francisco's legacy business data was trapped in PDF application forms, making it difficult to discover and explore the city's historic businesses.\n\n## Solution\n\n### Data Pipeline\n- Used LlamaParse to extract structured data from PDF applications\n- Cleaned and normalized business information\n- Built searchable database with rich metadata\n\n### User Experience\n- Created engaging visual interface for browsing businesses\n- Added filtering by neighborhood, business type, and year established\n- Implemented search functionality\n\n## Impact\n- Made civic data accessible and useful\n- Demonstrated practical LLM applications for document processing\n- Created reusable pipeline for similar civic tech projects\n\n## Tech Stack\n- LlamaParse for PDF extraction\n- Vector search for semantic queries\n- Modern web framework for UI	["LlamaParse","PDF Processing","Civic Tech","Vector Search","Full Stack"]	t	4	\N	\N	\N	hackathon
1	published	My Little Soda - Autonomous Coding Agent	my-little-soda	Open Source	Creator & Maintainer	2025	Ongoing	GitHub Issues-driven autonomous coding tool that uses LLMs to automatically implement features and fix bugs.	## Overview\n\nBuilt an autonomous coding agent that monitors GitHub Issues and automatically generates pull requests with working code implementations.\n\n## Technical Implementation\n- Integrates with GitHub API for issue tracking\n- Uses Claude/GPT for code generation\n- Implements automated testing and validation\n- Handles PR creation and code review workflows\n\n## Impact\n- Demonstrates practical agent architecture patterns\n- Reduces time from issue creation to implementation\n- Open source tool for developer productivity	["Python","GitHub API","Claude","GPT","Autonomous Agents"]	t	1	\N	https://github.com/johnhkchen/my-little-soda	\N	open-source
3	published	Tech Event Analyzer - Hackathon Project	tech-event-analyzer	Hackathon Project	Full Stack Developer	2024	4 hours	Discovered undocumented Lu.ma pagination API and built analyzer to identify which tech companies consistently provide food at events. Found Cloudflare, AWS, and GitHub as top sponsors.	## Problem\n\nTech event attendees need to know which events are worth attending beyond just the topic.\n\n## Solution\n\nBuilt a scraper and analyzer that:\n- Discovered and utilized undocumented Lu.ma pagination API endpoint\n- Extracted event data including sponsors and amenities\n- Identified patterns in sponsor behavior\n- Ranked companies by event quality metrics\n\n## Key Findings\n- Cloudflare, AWS, and GitHub consistently budget for attendee food\n- Correlation between food quality and event engagement\n- Useful for event planning and attendee decision-making\n\n## Technologies\n- API reverse engineering\n- Data analysis and visualization\n- Pattern recognition	["Python","API Scraping","Data Analysis","Lu.ma"]	t	3	\N	\N	\N	hackathon
7	published	Fitness Planner - Vector Search Application	fitness-planner	Hackathon Project	Full Stack Developer	2024	4 hours	AI-powered fitness routine suggester using Weaviate vector database. Transforms user descriptions into personalized workout plans.	## Concept\n\nNatural language fitness planning: describe your goals and fitness level, get personalized workout routines.\n\n## Technical Implementation\n\n### Vector Search\n- Used Weaviate for semantic workout search\n- Embedded fitness routines with descriptions\n- Implemented semantic similarity matching\n\n### Example Queries\n- "out of shape 30 year old couch to 5k"\n- "strength training for beginners"\n- "low impact cardio for seniors"\n\n### Structured Output\n- Generated progressive workout plans\n- Included exercise descriptions and modifications\n- Suggested timelines and milestones\n\n## Learning\n- Practical vector database implementation\n- Semantic search for recommendation systems\n- Rapid prototyping with modern AI tools	["Weaviate","Vector Search","LLM","Full Stack","RAG"]	t	7	\N	\N	\N	hackathon
6	published	IdeaWall - HCI Research	ideawall-research	UC Davis Visualization Lab	Research Assistant	2015-2016	1 year 2 months	Research assistant on ACM CSCW paper about AI-augmented creative collaboration. Contributed to user studies, Mandarin-to-English copyediting, and publication process for IdeaWall system.	## Research Project\n\n**Published**: ACM Conference on Computer Supported Cooperative Work and Social Computing (CSCW '17)\n\n## Overview\n\nResearch assistant at UC Davis Visualization Lab working on IdeaWall, an intelligent system that augments verbal creative collaboration with real-time visual stimuli.\n\n## Contributions\n\n### User Studies\n- Conducted and facilitated user testing sessions\n- Helped coordinate study with 24 participants across 12 groups\n- Collected and documented research data\n\n### Publication Support\n- Mandarin-to-English copyediting for international collaboration\n- Assisted with paper revision and submission process\n- Contributed to getting paper accepted at competitive HCI venue\n\n### Technical Support\n- Assisted with real-time speech processing and information extraction system\n- Supported web search integration for contextual materials\n- Helped develop visual display system with three cognitive strategies\n\n## Research Impact\n- Junior author on paper demonstrating effectiveness of AI-assisted collaboration tools\n- Contributed to validating three cognitive strategies for visual facilitation\n- Helped establish foundation for future intelligent groupware systems\n\n## Skills Developed\n- Research methodology and user testing\n- Academic writing and publication process\n- Cross-cultural collaboration and translation\n- Human-computer interaction design	["HCI Research","Real-time Processing","User Studies","Data Visualization","Academic Writing"]	t	4	\N	\N	http://dl.acm.org/citation.cfm?id=2998208	research
8	published	Univar Solutions - Data Engineering	potion-data-engineering	Potion	Data Analyst (Contract)	2022	Contract	Contract data analyst for Potion, a software consultancy serving Univar Solutions. Built data reconciliation pipeline for chemical formula database and introduced Jupyter notebooks to annotation team.	## Challenge\n\nChemical formulation database at Univar Solutions needed cleanup, but manual edits lost connection to original IDs, making it impossible to write changes back.\n\n## Solution\n\n### Data Pipeline\n- Built reconciliation system matching outdated names to original IDs\n- Enabled bidirectional sync between golden dataset and production DB\n- Automated cleanup and consolidation of redundant labels\n\n### Team Enablement\n- Introduced Jupyter notebooks to annotation team\n- Created tools for efficient data cleanup\n- Trained team on data engineering best practices\n\n## Impact\n- Saved hundreds of hours of manual work\n- Made previously impossible database updates feasible\n- Improved data quality for Univar Solutions chemical supply network\n\n## Technologies\n- Data engineering and ETL\n- Database reconciliation algorithms\n- Jupyter for collaborative data work\n\n*Contract role through Potion, providing services to Univar Solutions*	["Python","Jupyter","Data Engineering","ETL","Database Systems"]	t	2	\N	\N	\N	employment
5	published	Piper - STEM Learning Platform	piper	Piper, Inc.	Software Engineer	2018-2021	3 years 5 months	Full-stack engineer on STEM learning platform combining hardware and software. Key contributor to expansion pack release, PiperStory (Minecraft-based game mode), and PiperCode (Blockly/Scratch teaching tool).	## Role & Responsibilities\n\nFull-stack engineer on Python-based STEM learning platform for K-12 education, combining Raspberry Pi hardware with custom software.\n\n## Key Projects\n\n### PiperStory Game Mode\n- Raspberry Pi-based modded Minecraft system\n- Built on top of Minecraft Pi Edition\n- Created educational game experiences for kids learning electronics and programming\n\n### PiperCode Teaching Tool\n- React-based Electron app using Blockly/Scratch\n- Visual programming interface for kids to learn coding concepts\n- Integrated with hardware projects\n\n### Expansion Pack (DLC)\n- Key contributor to major content release as part of core dev team\n- Improved customer engagement and retention\n- Extended platform capabilities with new features\n\n### Infrastructure & Analytics\n- **Analytics Dashboard**: Set up SQL and Amplitude for marketing, QA, and dev-ops intelligence\n- **Survey System**: Developed FERPA-compliant web service using JavaScript, Google Apps Engine, and Firebase\n- **Technical Blog**: Created content exploring CS and EE concepts through DIY projects\n\n## Impact\n- Part of small team delivering STEM education to K-12 students nationwide\n- Contributed to product development across hardware/software integration\n- Built tools that made learning electronics and programming accessible to kids\n\n*Note: Piper is no longer in production as of 2021*	["Python","JavaScript","SQL","Firebase","Google Apps Engine","Amplitude","Game Development"]	t	3	\N	\N	\N	employment
2	published	CS Club - Community Building & Education	cs-club-ccsf	City College of San Francisco	Officer	2023-present	2 years+	Treasurer and advisor for CS Club. Built https://ccsf-cs.club using Astro, achieving #1 Google ranking for CS clubs in SF. Led student teams attending tech events across the Bay Area.	## Overview\n\nServed as treasurer and advisor for CS Club at CCSF, supporting student leaders while contributing technical expertise and event coordination.\n\n## Key Contributions\n\n### Website & Online Presence\n- Built https://ccsf-cs.club using Astro framework\n- Achieved #1 Google ranking for "CS club" searches in San Francisco region\n- Created resource hub for students learning modern web development\n- Introduced students to Astro, helping them build professional portfolios\n\n### Event Leadership\n- Led student teams attending 100+ tech events across the Bay Area\n- Organized group attendance at hackathons, workshops, and tech meetups\n- Connected students with SF tech community opportunities\n- Mentored first-time hackathon participants\n\n### Administrative Support\n- Managed club finances as treasurer\n- Provided guidance while empowering younger students to take leadership roles\n- Supported student-led initiatives with financial and technical expertise\n\n## Impact\n- **Student Success**: Supported students transferring to top universities including UC Berkeley over 2 consecutive years\n- **Community Growth**: Helped build thriving community connecting CCSF students to tech careers\n- **Technical Education**: Created pathways for non-traditional students into tech through accessible resources and mentorship\n\n*2023-present*	["Astro","Community Building","Education","Event Management"]	t	1	\N	https://ccsf-cs.club	\N	education
\.


--
-- Name: directus_activity_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_activity_id_seq', 198, true);


--
-- Name: directus_fields_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_fields_id_seq', 58, true);


--
-- Name: directus_notifications_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_notifications_id_seq', 1, false);


--
-- Name: directus_permissions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_permissions_id_seq', 5, true);


--
-- Name: directus_presets_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_presets_id_seq', 3, true);


--
-- Name: directus_relations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_relations_id_seq', 1, false);


--
-- Name: directus_revisions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_revisions_id_seq', 166, true);


--
-- Name: directus_settings_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_settings_id_seq', 1, true);


--
-- Name: directus_webhooks_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.directus_webhooks_id_seq', 1, false);


--
-- Name: posts_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.posts_id_seq', 8, true);


--
-- Name: profile_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.profile_id_seq', 1, true);


--
-- Name: skills_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.skills_id_seq', 21, true);


--
-- Name: social_links_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.social_links_id_seq', 3, true);


--
-- Name: work_projects_id_seq; Type: SEQUENCE SET; Schema: public; Owner: homelab
--

SELECT pg_catalog.setval('public.work_projects_id_seq', 8, true);


--
-- Name: directus_access directus_access_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_access
    ADD CONSTRAINT directus_access_pkey PRIMARY KEY (id);


--
-- Name: directus_activity directus_activity_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_activity
    ADD CONSTRAINT directus_activity_pkey PRIMARY KEY (id);


--
-- Name: directus_collections directus_collections_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_collections
    ADD CONSTRAINT directus_collections_pkey PRIMARY KEY (collection);


--
-- Name: directus_comments directus_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_comments
    ADD CONSTRAINT directus_comments_pkey PRIMARY KEY (id);


--
-- Name: directus_dashboards directus_dashboards_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_dashboards
    ADD CONSTRAINT directus_dashboards_pkey PRIMARY KEY (id);


--
-- Name: directus_extensions directus_extensions_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_extensions
    ADD CONSTRAINT directus_extensions_pkey PRIMARY KEY (id);


--
-- Name: directus_fields directus_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_fields
    ADD CONSTRAINT directus_fields_pkey PRIMARY KEY (id);


--
-- Name: directus_files directus_files_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_files
    ADD CONSTRAINT directus_files_pkey PRIMARY KEY (id);


--
-- Name: directus_flows directus_flows_operation_unique; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_flows
    ADD CONSTRAINT directus_flows_operation_unique UNIQUE (operation);


--
-- Name: directus_flows directus_flows_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_flows
    ADD CONSTRAINT directus_flows_pkey PRIMARY KEY (id);


--
-- Name: directus_folders directus_folders_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_folders
    ADD CONSTRAINT directus_folders_pkey PRIMARY KEY (id);


--
-- Name: directus_migrations directus_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_migrations
    ADD CONSTRAINT directus_migrations_pkey PRIMARY KEY (version);


--
-- Name: directus_notifications directus_notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_notifications
    ADD CONSTRAINT directus_notifications_pkey PRIMARY KEY (id);


--
-- Name: directus_operations directus_operations_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_operations
    ADD CONSTRAINT directus_operations_pkey PRIMARY KEY (id);


--
-- Name: directus_operations directus_operations_reject_unique; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_operations
    ADD CONSTRAINT directus_operations_reject_unique UNIQUE (reject);


--
-- Name: directus_operations directus_operations_resolve_unique; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_operations
    ADD CONSTRAINT directus_operations_resolve_unique UNIQUE (resolve);


--
-- Name: directus_panels directus_panels_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_panels
    ADD CONSTRAINT directus_panels_pkey PRIMARY KEY (id);


--
-- Name: directus_permissions directus_permissions_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_permissions
    ADD CONSTRAINT directus_permissions_pkey PRIMARY KEY (id);


--
-- Name: directus_policies directus_policies_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_policies
    ADD CONSTRAINT directus_policies_pkey PRIMARY KEY (id);


--
-- Name: directus_presets directus_presets_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_presets
    ADD CONSTRAINT directus_presets_pkey PRIMARY KEY (id);


--
-- Name: directus_relations directus_relations_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_relations
    ADD CONSTRAINT directus_relations_pkey PRIMARY KEY (id);


--
-- Name: directus_revisions directus_revisions_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_revisions
    ADD CONSTRAINT directus_revisions_pkey PRIMARY KEY (id);


--
-- Name: directus_roles directus_roles_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_roles
    ADD CONSTRAINT directus_roles_pkey PRIMARY KEY (id);


--
-- Name: directus_sessions directus_sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_sessions
    ADD CONSTRAINT directus_sessions_pkey PRIMARY KEY (token);


--
-- Name: directus_settings directus_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings
    ADD CONSTRAINT directus_settings_pkey PRIMARY KEY (id);


--
-- Name: directus_shares directus_shares_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_shares
    ADD CONSTRAINT directus_shares_pkey PRIMARY KEY (id);


--
-- Name: directus_translations directus_translations_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_translations
    ADD CONSTRAINT directus_translations_pkey PRIMARY KEY (id);


--
-- Name: directus_users directus_users_email_unique; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_users
    ADD CONSTRAINT directus_users_email_unique UNIQUE (email);


--
-- Name: directus_users directus_users_external_identifier_unique; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_users
    ADD CONSTRAINT directus_users_external_identifier_unique UNIQUE (external_identifier);


--
-- Name: directus_users directus_users_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_users
    ADD CONSTRAINT directus_users_pkey PRIMARY KEY (id);


--
-- Name: directus_users directus_users_token_unique; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_users
    ADD CONSTRAINT directus_users_token_unique UNIQUE (token);


--
-- Name: directus_versions directus_versions_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_versions
    ADD CONSTRAINT directus_versions_pkey PRIMARY KEY (id);


--
-- Name: directus_webhooks directus_webhooks_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_webhooks
    ADD CONSTRAINT directus_webhooks_pkey PRIMARY KEY (id);


--
-- Name: posts posts_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.posts
    ADD CONSTRAINT posts_pkey PRIMARY KEY (id);


--
-- Name: profile profile_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.profile
    ADD CONSTRAINT profile_pkey PRIMARY KEY (id);


--
-- Name: skills skills_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.skills
    ADD CONSTRAINT skills_pkey PRIMARY KEY (id);


--
-- Name: social_links social_links_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.social_links
    ADD CONSTRAINT social_links_pkey PRIMARY KEY (id);


--
-- Name: work_projects work_projects_pkey; Type: CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.work_projects
    ADD CONSTRAINT work_projects_pkey PRIMARY KEY (id);


--
-- Name: directus_access directus_access_policy_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_access
    ADD CONSTRAINT directus_access_policy_foreign FOREIGN KEY (policy) REFERENCES public.directus_policies(id) ON DELETE CASCADE;


--
-- Name: directus_access directus_access_role_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_access
    ADD CONSTRAINT directus_access_role_foreign FOREIGN KEY (role) REFERENCES public.directus_roles(id) ON DELETE CASCADE;


--
-- Name: directus_access directus_access_user_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_access
    ADD CONSTRAINT directus_access_user_foreign FOREIGN KEY ("user") REFERENCES public.directus_users(id) ON DELETE CASCADE;


--
-- Name: directus_collections directus_collections_group_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_collections
    ADD CONSTRAINT directus_collections_group_foreign FOREIGN KEY ("group") REFERENCES public.directus_collections(collection);


--
-- Name: directus_comments directus_comments_user_created_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_comments
    ADD CONSTRAINT directus_comments_user_created_foreign FOREIGN KEY (user_created) REFERENCES public.directus_users(id) ON DELETE SET NULL;


--
-- Name: directus_comments directus_comments_user_updated_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_comments
    ADD CONSTRAINT directus_comments_user_updated_foreign FOREIGN KEY (user_updated) REFERENCES public.directus_users(id);


--
-- Name: directus_dashboards directus_dashboards_user_created_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_dashboards
    ADD CONSTRAINT directus_dashboards_user_created_foreign FOREIGN KEY (user_created) REFERENCES public.directus_users(id) ON DELETE SET NULL;


--
-- Name: directus_files directus_files_folder_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_files
    ADD CONSTRAINT directus_files_folder_foreign FOREIGN KEY (folder) REFERENCES public.directus_folders(id) ON DELETE SET NULL;


--
-- Name: directus_files directus_files_modified_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_files
    ADD CONSTRAINT directus_files_modified_by_foreign FOREIGN KEY (modified_by) REFERENCES public.directus_users(id);


--
-- Name: directus_files directus_files_uploaded_by_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_files
    ADD CONSTRAINT directus_files_uploaded_by_foreign FOREIGN KEY (uploaded_by) REFERENCES public.directus_users(id);


--
-- Name: directus_flows directus_flows_user_created_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_flows
    ADD CONSTRAINT directus_flows_user_created_foreign FOREIGN KEY (user_created) REFERENCES public.directus_users(id) ON DELETE SET NULL;


--
-- Name: directus_folders directus_folders_parent_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_folders
    ADD CONSTRAINT directus_folders_parent_foreign FOREIGN KEY (parent) REFERENCES public.directus_folders(id);


--
-- Name: directus_notifications directus_notifications_recipient_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_notifications
    ADD CONSTRAINT directus_notifications_recipient_foreign FOREIGN KEY (recipient) REFERENCES public.directus_users(id) ON DELETE CASCADE;


--
-- Name: directus_notifications directus_notifications_sender_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_notifications
    ADD CONSTRAINT directus_notifications_sender_foreign FOREIGN KEY (sender) REFERENCES public.directus_users(id);


--
-- Name: directus_operations directus_operations_flow_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_operations
    ADD CONSTRAINT directus_operations_flow_foreign FOREIGN KEY (flow) REFERENCES public.directus_flows(id) ON DELETE CASCADE;


--
-- Name: directus_operations directus_operations_reject_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_operations
    ADD CONSTRAINT directus_operations_reject_foreign FOREIGN KEY (reject) REFERENCES public.directus_operations(id);


--
-- Name: directus_operations directus_operations_resolve_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_operations
    ADD CONSTRAINT directus_operations_resolve_foreign FOREIGN KEY (resolve) REFERENCES public.directus_operations(id);


--
-- Name: directus_operations directus_operations_user_created_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_operations
    ADD CONSTRAINT directus_operations_user_created_foreign FOREIGN KEY (user_created) REFERENCES public.directus_users(id) ON DELETE SET NULL;


--
-- Name: directus_panels directus_panels_dashboard_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_panels
    ADD CONSTRAINT directus_panels_dashboard_foreign FOREIGN KEY (dashboard) REFERENCES public.directus_dashboards(id) ON DELETE CASCADE;


--
-- Name: directus_panels directus_panels_user_created_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_panels
    ADD CONSTRAINT directus_panels_user_created_foreign FOREIGN KEY (user_created) REFERENCES public.directus_users(id) ON DELETE SET NULL;


--
-- Name: directus_permissions directus_permissions_policy_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_permissions
    ADD CONSTRAINT directus_permissions_policy_foreign FOREIGN KEY (policy) REFERENCES public.directus_policies(id) ON DELETE CASCADE;


--
-- Name: directus_presets directus_presets_role_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_presets
    ADD CONSTRAINT directus_presets_role_foreign FOREIGN KEY (role) REFERENCES public.directus_roles(id) ON DELETE CASCADE;


--
-- Name: directus_presets directus_presets_user_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_presets
    ADD CONSTRAINT directus_presets_user_foreign FOREIGN KEY ("user") REFERENCES public.directus_users(id) ON DELETE CASCADE;


--
-- Name: directus_revisions directus_revisions_activity_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_revisions
    ADD CONSTRAINT directus_revisions_activity_foreign FOREIGN KEY (activity) REFERENCES public.directus_activity(id) ON DELETE CASCADE;


--
-- Name: directus_revisions directus_revisions_parent_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_revisions
    ADD CONSTRAINT directus_revisions_parent_foreign FOREIGN KEY (parent) REFERENCES public.directus_revisions(id);


--
-- Name: directus_revisions directus_revisions_version_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_revisions
    ADD CONSTRAINT directus_revisions_version_foreign FOREIGN KEY (version) REFERENCES public.directus_versions(id) ON DELETE CASCADE;


--
-- Name: directus_roles directus_roles_parent_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_roles
    ADD CONSTRAINT directus_roles_parent_foreign FOREIGN KEY (parent) REFERENCES public.directus_roles(id);


--
-- Name: directus_sessions directus_sessions_share_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_sessions
    ADD CONSTRAINT directus_sessions_share_foreign FOREIGN KEY (share) REFERENCES public.directus_shares(id) ON DELETE CASCADE;


--
-- Name: directus_sessions directus_sessions_user_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_sessions
    ADD CONSTRAINT directus_sessions_user_foreign FOREIGN KEY ("user") REFERENCES public.directus_users(id) ON DELETE CASCADE;


--
-- Name: directus_settings directus_settings_project_logo_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings
    ADD CONSTRAINT directus_settings_project_logo_foreign FOREIGN KEY (project_logo) REFERENCES public.directus_files(id);


--
-- Name: directus_settings directus_settings_public_background_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings
    ADD CONSTRAINT directus_settings_public_background_foreign FOREIGN KEY (public_background) REFERENCES public.directus_files(id);


--
-- Name: directus_settings directus_settings_public_favicon_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings
    ADD CONSTRAINT directus_settings_public_favicon_foreign FOREIGN KEY (public_favicon) REFERENCES public.directus_files(id);


--
-- Name: directus_settings directus_settings_public_foreground_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings
    ADD CONSTRAINT directus_settings_public_foreground_foreign FOREIGN KEY (public_foreground) REFERENCES public.directus_files(id);


--
-- Name: directus_settings directus_settings_public_registration_role_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings
    ADD CONSTRAINT directus_settings_public_registration_role_foreign FOREIGN KEY (public_registration_role) REFERENCES public.directus_roles(id) ON DELETE SET NULL;


--
-- Name: directus_settings directus_settings_storage_default_folder_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_settings
    ADD CONSTRAINT directus_settings_storage_default_folder_foreign FOREIGN KEY (storage_default_folder) REFERENCES public.directus_folders(id) ON DELETE SET NULL;


--
-- Name: directus_shares directus_shares_collection_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_shares
    ADD CONSTRAINT directus_shares_collection_foreign FOREIGN KEY (collection) REFERENCES public.directus_collections(collection) ON DELETE CASCADE;


--
-- Name: directus_shares directus_shares_role_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_shares
    ADD CONSTRAINT directus_shares_role_foreign FOREIGN KEY (role) REFERENCES public.directus_roles(id) ON DELETE CASCADE;


--
-- Name: directus_shares directus_shares_user_created_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_shares
    ADD CONSTRAINT directus_shares_user_created_foreign FOREIGN KEY (user_created) REFERENCES public.directus_users(id) ON DELETE SET NULL;


--
-- Name: directus_users directus_users_role_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_users
    ADD CONSTRAINT directus_users_role_foreign FOREIGN KEY (role) REFERENCES public.directus_roles(id) ON DELETE SET NULL;


--
-- Name: directus_versions directus_versions_collection_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_versions
    ADD CONSTRAINT directus_versions_collection_foreign FOREIGN KEY (collection) REFERENCES public.directus_collections(collection) ON DELETE CASCADE;


--
-- Name: directus_versions directus_versions_user_created_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_versions
    ADD CONSTRAINT directus_versions_user_created_foreign FOREIGN KEY (user_created) REFERENCES public.directus_users(id) ON DELETE SET NULL;


--
-- Name: directus_versions directus_versions_user_updated_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_versions
    ADD CONSTRAINT directus_versions_user_updated_foreign FOREIGN KEY (user_updated) REFERENCES public.directus_users(id);


--
-- Name: directus_webhooks directus_webhooks_migrated_flow_foreign; Type: FK CONSTRAINT; Schema: public; Owner: homelab
--

ALTER TABLE ONLY public.directus_webhooks
    ADD CONSTRAINT directus_webhooks_migrated_flow_foreign FOREIGN KEY (migrated_flow) REFERENCES public.directus_flows(id) ON DELETE SET NULL;


--
-- PostgreSQL database dump complete
--

\unrestrict TG2nhZgrjloKh7jlMVecLEprHw1a3hDg39djzWHnwuHlz0BazsrNAbub3aaOiFX

