diff --git a/database/init.sql b/database/init.sql
new file mode 100644
index 0000000..14924f6
--- /dev/null
+++ b/database/init.sql
@@ -0,0 +1,2727 @@
+--
+-- 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":"
This is a full-stack TypeScript application demonstrating how to use Directus as a headless CMS. The architecture consists of:
\\n\\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!
"} {"title":"Welcome to Astro + Hono + Directus","content":"This is a full-stack TypeScript application demonstrating how to use Directus as a headless CMS. The architecture consists of:
\\n\\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
+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":"This is a full-stack TypeScript application demonstrating how to use Directus as a headless CMS. The architecture consists of:
\\n\\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!
","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":"Headless CMS architecture separates content management from presentation:
\\n\\n- Content editors use a friendly UI (Directus)
\\n- Developers fetch content via API
\\n- Frontend can be any technology
\\n- Content is reusable across multiple platforms
\\n
\\nPerfect for modern web applications!
","published":true} {"title":"Why Use a Headless CMS?","content":"Headless CMS architecture separates content management from presentation:
\\n\\n- Content editors use a friendly UI (Directus)
\\n- Developers fetch content via API
\\n- Frontend can be any technology
\\n- Content is reusable across multiple platforms
\\n
\\nPerfect for modern web applications!
","published":true} \N \N
+13 15 posts 3 {"title":"Building with TypeScript","content":"This entire stack is built with TypeScript:
\\n\\n- Type-safe API with Hono
\\n- Type-safe frontend with Astro
\\n- Type-safe Directus SDK
\\n
\\nTypeScript catches errors during development, not in production!
"} {"title":"Building with TypeScript","content":"This entire stack is built with TypeScript:
\\n\\n- Type-safe API with Hono
\\n- Type-safe frontend with Astro
\\n- Type-safe Directus SDK
\\n
\\nTypeScript catches errors during development, not in production!
"} \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":"This entire stack is built with TypeScript:
\\n\\n- Type-safe API with Hono
\\n- Type-safe frontend with Astro
\\n- Type-safe Directus SDK
\\n
\\nTypeScript catches errors during development, not in production!
","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(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 {\\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\\n \\n\\n {project.data.description}
\\n\\n \\n {project.data.technologies.map(tech => (\\n \\n ))}\\n
\\n\\n {contentHtml && (\\n \\n \\n \\n )}\\n\\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(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 {\\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\\n \\n\\n {project.data.description}
\\n\\n \\n {project.data.technologies.map(tech => (\\n \\n ))}\\n
\\n\\n {contentHtml && (\\n \\n \\n \\n )}\\n\\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('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 {\\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\\n {project.data.title}
\\n {project.data.role} @ {project.data.company}
\\n\\n {project.data.technologies.map(tech => (\\n \\n ))}\\n\\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('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 {\\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\\n {project.data.title}
\\n {project.data.role} @ {project.data.company}
\\n\\n {project.data.technologies.map(tech => (\\n \\n ))}\\n\\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('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 {\\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\\n {project.data.title}
\\n {project.data.role} @ {project.data.company}
\\n\\n {project.data.technologies.map(tech => (\\n \\n ))}\\n\\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('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 {\\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\\n {project.data.title}
\\n {project.data.role} @ {project.data.company}
\\n\\n {project.data.technologies.map(tech => (\\n \\n ))}\\n\\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('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('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('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('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('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('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('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('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('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('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
+