- Add Subdomain Routing section to AGENTS.md with route placement, site context, API routing, and auth boundary guidance for future tasks - Add scripts/verify-subdomains.sh for post-deployment verification of DNS, HTTPS, appcast regression, and SSL certificates
4.1 KiB
4.1 KiB
Agent Guidelines for freno-dev
Tech Stack
- Framework: SolidJS with SolidStart (Vinxi)
- Routing: @solidjs/router
- API: tRPC v10 with Zod validation
- Database: libSQL/Turso with SQL queries
- Styling: TailwindCSS v4
- Runtime: Bun (Node >=22)
- Deployment: Vercel preset
Code Style
Naming Conventions
- Files/Components: PascalCase (e.g.,
Button.tsx,UserProfile.tsx) - Variables/Functions: camelCase (e.g.,
getUserID,displayName) - Types/Interfaces: PascalCase (e.g.,
User,ButtonProps) - Constants: camelCase or UPPER_SNAKE_CASE for true constants
Imports
- Prefer named imports from solid-js:
import { createSignal, Show, For } from "solid-js" - Use
~/*path alias for src imports:import { api } from "~/lib/api" - Group imports: external deps → solid-js → local (~/)
SolidJS Patterns (NOT React!)
- State: Use
createSignal()notuseState. Always call signals:count()to read - Effects: Use
createEffect()notuseEffect. Auto-tracks dependencies (no array) - Conditionals: Prefer
<Show when={condition()}>over&&or ternary - Lists: Prefer
<For each={items()}>over.map() - Forms: Use
onInput(notonChange), accesse.currentTarget.value - Refs: Use
let refbinding orcreateSignal()for reactive refs
TypeScript
- Strict mode enabled - always type function params and returns
- Use interfaces for props:
export interface ButtonProps extends JSX.HTMLAttributes<T> - Use
splitProps()for component prop destructuring - Prefer explicit types over
any- useunknownif type truly unknown - Database types: Cast with
as unknown as Userfor SQL results
API/Server Patterns
- tRPC routers: Export from
src/server/api/routers/*.ts - Procedures: Use
.query()for reads,.mutation()for writes - Validation: Use Zod schemas in
.input()- validate all user input - Auth: Extract userId with
await getUserID(ctx.event.nativeEvent) - Errors: Throw
TRPCErrorwith proper codes (UNAUTHORIZED, NOT_FOUND, BAD_REQUEST) - Database: Use
ConnectionFactory()singleton, parameterized queries only
Error Handling
- Use TRPCError with semantic codes on server
- Validate inputs with Zod schemas before processing
- Check auth state before mutations: throw UNAUTHORIZED if missing userId
- Return structured responses:
{ success: boolean, message?: string }
Comments
- Minimal comments - prefer self-documenting code
- JSDoc for exported functions/components only
- Inline comments for non-obvious logic only
File Organization
- Routes in
src/routes/(file-based routing) - Components in
src/components/(reusable) or co-located with routes - API routers in
src/server/api/routers/ - Types in
src/types/(shared types) or co-located - Utils in
src/lib/orsrc/server/utils.ts
Subdomain Routing
This project serves four product subdomains (nessa.freno.me, lineage.freno.me, gaze.freno.me, inputhalo.freno.me) plus the personal site on freno.me. See docs/subdomain-setup.md for DNS/Vercel configuration.
- Route placement: Subdomain pages live under
src/routes/<prefix>/*(e.g.src/routes/nessa/...). Thevercel.jsonhost-based rewrites map each subdomain to its prefix. - Site context: Use
useSite()(SolidJS) orgetSiteFromEvent/getSiteFromRequest(server) fromsrc/lib/site-context.tsto detect the current site. Never host-snoop in route files — SolidStart's router can't match on host. - API routes:
/api/*is a shared pool — subdomain API requests pass through to existing routes via vercel.json pass-through rewrites (ordering matters). - Auth: Host-scoped only — no cookie domain broadening.
Key Differences from React
See src/lib/SOLID-PATTERNS.md for comprehensive React→Solid conversion guide. Key gotchas:
- Signals must be called with
()to read value onChange→onInputfor real-time input updatesuseEffect→createEffect(auto-tracking, no deps array)Link→Acomponent from @solidjs/router- Server actions → tRPC procedures