Building a Real App on This Stack
This guide is for developers who want to use BasicSiteServer as the foundation for something real — a SaaS product, a client site, an internal tool, or any web app that needs to grow beyond the starter kit.
The core challenge this guide solves: keeping the template contract intact while building app-specific logic on top of it, without confusing your AI coding assistant or wasting tokens on noise.
The Mental Model
Think of the project in two distinct layers:
┌─────────────────────────────────────────┐
│ YOUR APP LAYER │
│ business logic, auth, database, │
│ your specific routes, your pages │
├─────────────────────────────────────────┤
│ TEMPLATE LAYER │
│ layout engine, static file serving, │
│ wwwroot structure, port/host config │
└─────────────────────────────────────────┘
The template layer never changes once you've set it up. Your app layer grows indefinitely. The mistake most developers make is mixing instructions for both layers into a single file — which means your AI assistant is reading rules about {{HEADER}} token replacement every time you ask it to add a Stripe webhook. That's wasted tokens and a source of confusion.
The solution is two separate instruction files.
The Two-File Pattern
File 1: CLAUDE.md
This file is the template contract. It tells your AI assistant what the template is, what it does, and what must never change. This file should never grow. It is sealed. If you find yourself wanting to add app-specific rules to it, stop — that content belongs in the second file.
File 2: APP.md (you create this)
This file is the app contract. It tells your AI assistant what your specific app is, what it does, and the rules that are specific to your project. APP.md lives at the root of your project alongside CLAUDE.md. They serve different purposes and never overlap.
Creating Your APP.md
Create APP.md at the project root before writing a single line of app code. Here is a starter template:
# APP.md — [Your App Name]
## What this app is
[One paragraph. What does it do? Who is it for?]
## Stack additions
These are added on top of Basic Site Server and are app-specific.
The template layer (see CLAUDE.md) remains unchanged.
- [e.g. SQLite via Microsoft.Data.Sqlite for user data]
- [e.g. BCrypt.Net for password hashing]
- [e.g. JWT bearer tokens for session management]
## App-specific routes
Routes added by this app (template routes in CLAUDE.md are separate):
- GET /dashboard → pages/dashboard.html (authenticated only)
- POST /api/login → Endpoints/AuthEndpoints.cs
- POST /api/signup → Endpoints/AuthEndpoints.cs
## App-specific pages
Pages added to wwwroot/pages/ by this app:
- dashboard.html
- login.html
- signup.html
- pricing.html
## Rules specific to this app
- All authenticated routes must check for a valid JWT before rendering
- Database access only through the repository pattern in /Data/
- No business logic in endpoint files — endpoints call services only
## Environment variables added by this app
Beyond PORT and HOST (which belong to the template):
- DB_PATH → path to the SQLite database file
- JWT_SECRET → secret key for signing tokens
- STRIPE_KEY → Stripe API key (never log this)
## What NOT to change
- Do not modify the layout engine (RenderPage / render_page)
- Do not modify wwwroot/layout.html, header.html, or footer.html structure
- Do not change how static files are served
How to Use Both Files With Your AI Assistant
When starting a session, your first message should reference both files explicitly:
Read CLAUDE.md and APP.md before doing anything.
CLAUDE.md defines the template layer — do not modify anything it describes.
APP.md defines this specific app. Today's task is: [your task].
This one instruction does three things:
- Loads the template contract so the assistant knows what to protect
- Loads the app context so it knows what it's building
- Gives it a single focused task for the session
Keep sessions focused. One session = one task. "Add the login endpoint" is a good session. "Add login, signup, dashboard, and Stripe integration" is a session that will bleed context and produce inconsistent results.
Graduating the Template — Step by Step
Step 1: Rename or fork your starter. Before writing any app code, decide: are you building one app, or do you want to reuse the starter for future projects? Option A — build directly in the starter folder. Option B — duplicate the starter and keep a clean copy. Option B is recommended if you plan to build multiple projects.
Step 2: Create APP.md before writing code. A blank APP.md with just the app name and one-line description is enough to start. You will fill it in as the app grows.
Step 3: Add pages before adding logic. Create your HTML page files in wwwroot/pages/, add navigation links to header.html, run the server and click through the pages. Confirm the layout engine wraps every page correctly before adding any endpoints, database, or authentication.
Step 4: Add endpoints one at a time. One file per feature area (auth, billing, users). Each file is self-contained. Register it in Program.cs / main.rs with one line. Add to APP.md as you go.
Step 5: Add dependencies deliberately. Each time you need a new package, add it to APP.md under "Stack additions" with a one-line reason. This disciplines you to add dependencies intentionally and keeps your AI assistant informed.
The Token Efficiency Rule
Every line in CLAUDE.md and APP.md costs tokens on every session. Write only what the AI needs to make correct decisions. Ask yourself before adding any line:
"If this line weren't here, would the AI do something wrong?"
If the answer is no, don't add it.
Good lines change behavior:
- All database access goes through /Data/UserRepository.cs only
- JWT tokens expire after 24 hours — do not change this value
- The layout engine must not be modified under any circumstances
Bad lines are noise:
- This is a SaaS application for managing tasks
- We are using C# because it is a compiled language
- Make sure the code is clean and readable
Common Mistakes to Avoid
Merging CLAUDE.md and APP.md into one file. Template rules are permanent. App rules evolve. Keeping them separate means you can update app rules without risking the template contract.
Adding app pages before creating APP.md. You'll lose track of what's template and what's app. Always create APP.md first.
Describing the whole app in a single session. One session, one task. The accumulated APP.md is your memory between sessions — not the conversation history.
Letting APP.md grow without pruning. If a feature was removed or refactored, remove its entry from APP.md. Stale entries actively mislead your AI assistant.
Modifying the layout engine to add app logic. If you need dynamic data in your layout, do it with a small JavaScript fetch call from the page rather than modifying the server-side layout function. Keep the template layer clean.
Example: Adding User Authentication
What you want: users can sign up, log in, and see a private dashboard.
Step 1 — add pages:
wwwroot/pages/login.html
wwwroot/pages/signup.html
wwwroot/pages/dashboard.html
Step 2 — update APP.md:
## App-specific pages
- login.html → public
- signup.html → public
- dashboard.html → requires valid JWT (enforced in endpoint, redirect if missing)
## App-specific routes
- POST /api/signup → Endpoints/AuthEndpoints.cs
- POST /api/login → Endpoints/AuthEndpoints.cs
- GET /api/me → Endpoints/AuthEndpoints.cs
## Stack additions
- BCrypt.Net-Next — password hashing
- System.IdentityModel.Tokens.Jwt — JWT creation and validation
Step 3 — Claude Code session:
Read CLAUDE.md and APP.md before doing anything.
CLAUDE.md defines the template — do not modify anything it describes.
Task: Create Endpoints/AuthEndpoints.cs with POST /api/signup and POST /api/login.
Store users in a List<User> in memory for now. Return a JWT on successful login.
Step 4 — next session, add the database:
Read CLAUDE.md and APP.md.
Task: Replace the in-memory user list in AuthEndpoints.cs with SQLite using
Microsoft.Data.Sqlite. DB path from DB_PATH env var. Schema: users table with
id, email, password_hash, created_at.
One task per session. APP.md grows with each session. The template never changes.
File Reference
CLAUDE.md— provided with BasicSiteServer, sealed at setup, lives at project rootAPP.md— you create this before first app code, lives at project rootwwwroot/pages/*.html— you and AI add these as features are builtEndpoints/*.csorsrc/endpoints/*.rs— one file per feature area
justhtml