MyPortfolio fullstack-js
Guidelines for implementing hover/elevation interactions, layout constraints, sidebar setup, and visual styling.
install
source · Clone the upstream repo
git clone https://github.com/KartikSharma4448/MyPortfolio
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/KartikSharma4448/MyPortfolio "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.local/skills/fullstack-js" ~/.claude/skills/kartiksharma4448-myportfolio-fullstack-js && rm -rf "$T"
manifest:
.local/skills/fullstack-js/SKILL.mdsource content
Always follow these guidelines when building a full-stack JavaScript application:
Architecture
- Follow modern web application patterns and best-practices.
- Put as much of the app in the frontend as possible. The backend should only be responsible for data persistence and making API calls.
- Minimize the number of files. Collapse similar components into a single file.
- If the app is complex and requires functionality that can't be done in a single request, it is okay to stub out the backend and implement the frontend first.
Types
- Always think through and generate the data model first in
to ensure consistency between frontend and backend. Do this before writing any other code.shared/schema.ts - Keep the data model as simple as possible (e.g. don't add createdAt and updatedAt fields unless it is strictly necessary).
- For each model, additionally write:
- The insert schema using
fromcreateInsertSchema
. Usedrizzle-zod
to exclude any auto-generated fields..omit - The insert type using
z.infer<typeof insertSchema> - The select type using
.typeof table.$inferSelect
- The insert schema using
- Common pitfalls to avoid:
- When writing array columns in the Drizzle schema, always call
as a method on the column type, not as a wrapper function. That is, do.array()
instead oftext().array()
.array(text())
- When writing array columns in the Drizzle schema, always call
Storage
- Make sure to update
inIStorage
to accommodate any storage CRUD operations you need in the application.server/storage.ts - Ensure that storage interface uses the types from
.@shared/schema.ts
Backend
- After writing the storage interface, write the API routes in the
file.server/routes.ts - Always use the storage interface to do any CRUD operations. Keep the routes as thin as possible.
- Validate the request body using Zod schemas from
before passing it to the storage interface.drizzle-zod
Frontend
- Use
for routing on the frontend.wouter- If you need to add a new page, add them to the
directory and register them inclient/src/pages
.client/src/App.tsx - If there are multiple pages, use a sidebar for navigation. Use the
component or theLink
hook fromuseLocation
instead of modifying the window directly.wouter
- If you need to add a new page, add them to the
- For forms, always use shadcn's
hook anduseForm
component fromForm
which wraps@/components/ui/form
.react-hook-form- When appropriate, use the
fromzodResolver
to validate the form data using the appropriate insert schema from@hookform/resolvers/zod
.@shared/schema.ts - Use
to add validation rules to the insert schema..extend - Remember that the form component is controlled, ensure you pass default values to the
hook.useForm
- When appropriate, use the
- Always use
when fetching data.@tanstack/react-query- When appropriate, ensure you strongly type the query using the appropriate select type from
.@shared/schema.ts - Queries should not define their own queryFn as the default fetcher is already set up to work with the backend.
- Mutations should use apiRequest from
to make POST/PATCH/DELETE requests to the backend.@lib/queryClient- Always make sure to invalidate the cache by queryKey after a mutation is made. Don't forget to import
fromqueryClient
!@lib/queryClient - For hierarchical or variable query keys use an array for cache segments so cache invalidation works properly. That is, do queryKey: ['/api/recipes', id] instead of queryKey: [
]./api/recipes/${id}
- Always make sure to invalidate the cache by queryKey after a mutation is made. Don't forget to import
- Show a loading or skeleton state while queries (via
) or mutations (via.isLoading
) are being made.isPending - The template uses TanStack Query v5 which only allows the object form for query related functions. e.g.
instead ofuseQuery({ queryKey: ['key'] })useQuery(['key'])
- When appropriate, ensure you strongly type the query using the appropriate select type from
- Common pitfalls to avoid:
- The
hook is exported fromuseToast
.@/hooks/use-toast - If a form is failing to submit, try logging out
to see if there are form validation errors for fields that might not have associated form fields.form.formState.errors - DO NOT explicitly import React as the existing Vite setup has a JSX transformer that does it automatically.
- Use
to access environment variables on the frontend instead ofimport.meta.env.<ENV_VAR>
. Note that variables must be prefixed withprocess.env.<ENV_VAR>
in order for the env vars to be available on the frontend.VITE_ - <SelectItem> will throw an error if it has no value prop. Provide a value prop like this <SelectItem value="option1">
- The
- Add a
attribute to every HTML element that users can interact with (buttons, inputs, links, etc.) and to elements displaying meaningful information (user data, status messages, dynamic content, key values).data-testid- Use unique, descriptive identifiers following this pattern:
- Interactive elements:
(e.g.,{action}-{target}
,button-submit
,input-email
)link-profile - Display elements:
(e.g.,{type}-{content}
,text-username
,img-avatar
)status-payment
- Interactive elements:
- For dynamically generated elements (lists, grids, repeated components), append a unique identifier at the end:
{type}-{description}-{id}- Examples:
,card-product-${productId}
,row-user-${index}text-price-${itemId} - The dynamic identifier can be any unique value (database ID, index, key) as long as it's unique within that group
- Examples:
- Keep test IDs stable and descriptive of the element's purpose rather than its appearance or implementation details.
- Use unique, descriptive identifiers following this pattern:
Styling and Theming
- When defining custom properties in
that will be used by a tailwind config, always use H S% L% (space separated with percentages after Saturation and Lightness) (and do not wrap in hsl()).index.css- For example: --my-var: 23 10% 23%;
- Analyze the comments inside of
to determine how to set colors - replacing everyindex.css
placeholder with an appropriate color. Do NOT forget to replace every single instance ofred
. Pay attention to what you see in index.css.red - Use the
-prefixed paths to import shadcn components and hooks.@ - Use icons from
to signify actions and provide visual cues. Uselucide-react
for company logos.react-icons/si - User may attach assets (images, etc.) in their request.
- If the user asks you to include attached assets in the app, you can reference them in the frontend with the
import syntax.@assets/... - For example, if the user attached asset is at
, you can reference it in the frontend withattached_assets/example.png
.import examplePngPath from "@assets/example.png"
- If the user asks you to include attached assets in the app, you can reference them in the frontend with the
Dark Mode
- Set
in tailwind.config.ts and define color variables in :root and .dark CSS classesdarkMode: ["class"] - Create ThemeProvider with useState("light"), useEffect to toggle "dark" class on document.documentElement, and localStorage sync
- When not using utility class names configured in
, always use explicit light/dark variants for ALL visual properties:tailwind.config.ts
. When using utility classes configured in tailwind config, you can assume these already been configured to automatically adapt to dark mode.className="bg-white dark:bg-black text-black dark:text-white"
SEO
- Ensure every page has a unique, descriptive title tag (e.g., "Product Name - Category | Site Name")
- Add meta descriptions that summarize page content concisely
- Implement Open Graph tags for better social media sharing appearance
Running the Project
- The workflow named 'Start application' is already setup and runs
which starts an Express server for the backend and a Vite server for the frontend.npm run dev - After making edits, the workflow will automatically be restarted for you.
Forbidden Changes
- NEVER edit
:package.json- If you find yourself stuck and need to modify the scripts, ask the user before doing so.
- If you need to install packages, use the packager_install_tool.
Config File Guidance
- Do NOT modify the Vite setup (
andserver/vite.ts
) unless absolutely necessary. It is already configured to serve the frontend and backend on the same port and handles all the necessary setup for you. Don't add a proxy to the Vite server. All the aliases are already set up for you to import.vite.config.ts - Do NOT modify
unless absolutely necessary. It is pre-configured correctly.drizzle.config.ts
References
Before writing code, identify whether any reference below applies to the task. If it does, read it first.
- Use this reference when adding or changing hover/active/toggle interaction behavior, elevation effects, or overflow-sensitive interactive styling.references/hover_and_elevation.md
- Use this reference when building or modifying UI with Shadcn components (especially Button, Card, Badge, Avatar, and Textarea).references/shadcn_component_rules.md
- Use this reference when structuring page layouts, sections, spacing rhythm, and component alignment.references/layout_and_spacing.md
- Use this reference when building or modifying a sidebar.references/sidebar_rules.md
- Use this reference when choosing contrast, borders, shadows, pane/panel treatment, and hero image presentation.references/visual_style_and_contrast.md