Merge pull request #12 from manmohan659/feat/monorepo-scaffold

[codex] Scaffold monorepo platform layout
This commit is contained in:
Manmohan 2026-04-16 14:25:35 -04:00 committed by GitHub
commit a0533f2199
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1072 additions and 0 deletions

34
.env.example Normal file
View File

@ -0,0 +1,34 @@
POSTGRES_DB=samosachaat
POSTGRES_USER=samosachaat_admin
POSTGRES_PASSWORD=localdev
DATABASE_URL=postgresql+asyncpg://samosachaat_admin:localdev@localhost:5432/samosachaat
FRONTEND_PORT=3000
AUTH_PORT=8001
CHAT_API_PORT=8002
INFERENCE_PORT=8003
GRAFANA_PORT=3001
PROMETHEUS_PORT=9090
LOKI_PORT=3100
AUTH_SERVICE_URL=http://auth:8001
CHAT_API_URL=http://chat-api:8002
INFERENCE_SERVICE_URL=http://inference:8003
NEXTAUTH_URL=http://localhost:3000
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
JWT_ALGORITHM=RS256
JWT_PRIVATE_KEY=generate-an-rs256-private-key
JWT_PUBLIC_KEY=generate-the-matching-rs256-public-key
NEXTAUTH_SECRET=generate-a-random-secret
INTERNAL_API_KEY=generate-a-random-internal-api-key
HF_TOKEN=your-huggingface-token
MODEL_STORAGE_PATH=./models
DEFAULT_MODEL_TAG=samosachaat-d12
NANOCHAT_DTYPE=float32
NUM_WORKERS=1

8
.gitignore vendored
View File

@ -4,9 +4,17 @@ __pycache__/
dev-ignore/
report.md
eval_bundle/
models/
.terraform/
*.tfstate
*.tfstate.*
*.tfvars
*.tfvars.json
# Secrets
.env
.env.local
.env.*.local
# Local setup
CLAUDE.md

View File

@ -7,6 +7,30 @@ nanochat is the simplest experimental harness for training LLMs. It is designed
For questions about the repo, I recommend either using [DeepWiki](https://deepwiki.com/karpathy/nanochat) from Devin/Cognition to ask questions about the repo, or use the [Discussions tab](https://github.com/karpathy/nanochat/discussions), or come by the [#nanochat](https://discord.com/channels/1020383067459821711/1427295580895314031) channel on Discord.
## Platform monorepo scaffold
This repository now also carries the samosaChaat platform scaffold alongside the
original nanochat training code. The new top-level directories are organized for
service-oriented development:
- `services/` contains the frontend, auth, chat API, and inference services
- `contracts/` contains the shared OpenAPI and JSON schema contracts
- `db/migrations/` contains PostgreSQL schema bootstrap scripts
- `helm/` contains application and observability chart scaffolding
- `terraform/` contains shared modules plus `dev`, `uat`, and `prod` environment scaffolding
### Local platform quick start
1. Copy `.env.example` to `.env` and replace the placeholder secrets.
2. Start the local stack with `bash scripts/local-dev.sh`.
3. Seed the local database with `bash scripts/seed-db.sh`.
4. Open the placeholder frontend at [http://localhost:3000](http://localhost:3000).
The initial scaffold keeps the service topology stable for local development.
`services/auth`, `services/chat-api`, and `services/frontend` are placeholders
until their dedicated implementations land; the inference service is extracted on
the follow-up branch.
## Time-to-GPT-2 Leaderboard
Presently, the main focus of development is on tuning the pretraining stage, which takes the most amount of compute. Inspired by the modded-nanogpt repo and to incentivise progress and community collaboration, nanochat maintains a leaderboard for a "GPT-2 speedrun", which is the wall-clock time required to train a nanochat model to GPT-2 grade capability, as measured by the DCLM CORE score. The [runs/speedrun.sh](runs/speedrun.sh) script always reflects the reference way to train GPT-2 grade model and talk to it. The current leaderboard looks as follows:

View File

@ -0,0 +1,108 @@
openapi: 3.1.0
info:
title: samosaChaat Auth API
version: 0.1.0
description: >
Contract skeleton for the authentication service. OAuth providers, session
exchange, and user identity endpoints must conform to this document.
servers:
- url: http://auth:8001
paths:
/health:
get:
summary: Readiness probe for the auth service.
security: []
responses:
"200":
description: Auth service health.
content:
application/json:
schema:
type: object
properties:
status:
type: string
ready:
type: boolean
required:
- status
- ready
/auth/oauth/{provider}/start:
get:
summary: Begin an OAuth login flow.
parameters:
- $ref: "#/components/parameters/OAuthProvider"
responses:
"302":
description: Redirect to the provider authorization page.
/auth/oauth/{provider}/callback:
get:
summary: Complete an OAuth login flow.
parameters:
- $ref: "#/components/parameters/OAuthProvider"
- in: query
name: code
required: true
schema:
type: string
responses:
"200":
description: Session established.
content:
application/json:
schema:
type: object
properties:
user:
$ref: ../schemas/user.json
access_token:
type: string
required:
- user
- access_token
/auth/me:
get:
summary: Return the authenticated user profile.
security:
- sessionCookie: []
responses:
"200":
description: Current user profile.
content:
application/json:
schema:
$ref: ../schemas/user.json
/auth/token/refresh:
post:
summary: Exchange a refresh token for a new access token.
responses:
"200":
description: Refreshed session token pair.
content:
application/json:
schema:
type: object
properties:
access_token:
type: string
expires_in:
type: integer
required:
- access_token
- expires_in
components:
parameters:
OAuthProvider:
in: path
name: provider
required: true
schema:
type: string
enum:
- google
- github
securitySchemes:
sessionCookie:
type: apiKey
in: cookie
name: session

View File

@ -0,0 +1,153 @@
openapi: 3.1.0
info:
title: samosaChaat Chat API
version: 0.1.0
description: >
Contract skeleton for conversations, persisted message history, and chat
orchestration between the frontend and inference service.
servers:
- url: http://chat-api:8002
security:
- bearerAuth: []
paths:
/health:
get:
summary: Readiness probe for the chat API.
security: []
responses:
"200":
description: Chat API health.
content:
application/json:
schema:
type: object
properties:
status:
type: string
ready:
type: boolean
required:
- status
- ready
/conversations:
get:
summary: List the current user's conversations.
responses:
"200":
description: Conversation collection.
content:
application/json:
schema:
type: array
items:
$ref: ../schemas/conversation.json
post:
summary: Create a new conversation.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
model_tag:
type: string
required:
- title
- model_tag
responses:
"201":
description: Conversation created.
content:
application/json:
schema:
$ref: ../schemas/conversation.json
/conversations/{conversationId}:
get:
summary: Fetch a single conversation.
parameters:
- $ref: "#/components/parameters/ConversationId"
responses:
"200":
description: Conversation details.
content:
application/json:
schema:
$ref: ../schemas/conversation.json
patch:
summary: Update mutable conversation metadata.
parameters:
- $ref: "#/components/parameters/ConversationId"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
model_tag:
type: string
responses:
"200":
description: Updated conversation.
content:
application/json:
schema:
$ref: ../schemas/conversation.json
/conversations/{conversationId}/messages:
get:
summary: List persisted messages for a conversation.
parameters:
- $ref: "#/components/parameters/ConversationId"
responses:
"200":
description: Conversation message history.
content:
application/json:
schema:
type: array
items:
$ref: ../schemas/message.json
post:
summary: Append a message and begin streaming completion.
parameters:
- $ref: "#/components/parameters/ConversationId"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
message:
$ref: ../schemas/message.json
stream:
type: boolean
default: true
required:
- message
responses:
"200":
description: Server-sent token stream from the inference service.
content:
text/event-stream:
schema:
type: string
components:
parameters:
ConversationId:
in: path
name: conversationId
required: true
schema:
type: string
format: uuid
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT

View File

@ -0,0 +1,174 @@
openapi: 3.1.0
info:
title: samosaChaat Inference API
version: 0.1.0
description: >
Contract skeleton for the standalone inference microservice that streams
tokens and manages model weight lifecycle.
servers:
- url: http://inference:8003
paths:
/health:
get:
summary: Liveness and readiness probe.
responses:
"200":
description: Inference service health.
content:
application/json:
schema:
type: object
properties:
status:
type: string
ready:
type: boolean
current_model:
type:
- string
- "null"
required:
- status
- ready
/generate:
post:
summary: Stream generated tokens as server-sent events.
security:
- internalApiKey: []
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/GenerateRequest"
responses:
"200":
description: SSE response of token chunks and done marker.
content:
text/event-stream:
schema:
type: string
/models:
get:
summary: List available and loaded model weights.
security:
- internalApiKey: []
responses:
"200":
description: Model registry view.
content:
application/json:
schema:
type: object
properties:
current_model:
type:
- string
- "null"
models:
type: array
items:
$ref: "#/components/schemas/ModelInfo"
required:
- current_model
- models
/models/swap:
post:
summary: Drain workers and swap the loaded model weights.
security:
- internalApiKey: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
model_tag:
type: string
required:
- model_tag
responses:
"202":
description: Swap request accepted.
content:
application/json:
schema:
type: object
properties:
status:
type: string
current_model:
type: string
required:
- status
- current_model
/stats:
get:
summary: Worker pool and throughput statistics.
security:
- internalApiKey: []
responses:
"200":
description: Runtime worker statistics.
content:
application/json:
schema:
type: object
components:
securitySchemes:
internalApiKey:
type: apiKey
in: header
name: X-Internal-API-Key
schemas:
ChatMessage:
type: object
additionalProperties: false
properties:
role:
type: string
content:
type: string
required:
- role
- content
GenerateRequest:
type: object
additionalProperties: false
properties:
messages:
type: array
items:
$ref: "#/components/schemas/ChatMessage"
temperature:
type:
- number
- "null"
max_tokens:
type:
- integer
- "null"
top_k:
type:
- integer
- "null"
required:
- messages
ModelInfo:
type: object
additionalProperties: false
properties:
model_tag:
type: string
source:
type: string
path:
type: string
loaded:
type: boolean
required:
- model_tag
- source
- path
- loaded

View File

@ -0,0 +1,38 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Conversation",
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"user_id": {
"type": "string",
"format": "uuid"
},
"title": {
"type": "string"
},
"model_tag": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"user_id",
"title",
"model_tag",
"created_at",
"updated_at"
]
}

View File

@ -0,0 +1,47 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Message",
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"conversation_id": {
"type": "string",
"format": "uuid"
},
"role": {
"type": "string"
},
"content": {
"type": "string"
},
"token_count": {
"type": "integer",
"minimum": 0
},
"model_tag": {
"type": "string"
},
"inference_time_ms": {
"type": "integer",
"minimum": 0
},
"created_at": {
"type": "string",
"format": "date-time"
}
},
"required": [
"id",
"conversation_id",
"role",
"content",
"token_count",
"model_tag",
"inference_time_ms",
"created_at"
]
}

View File

@ -0,0 +1,58 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "User",
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"email": {
"type": "string",
"format": "email"
},
"name": {
"type": "string"
},
"avatar_url": {
"type": [
"string",
"null"
],
"format": "uri"
},
"provider": {
"type": "string"
},
"provider_id": {
"type": "string"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"updated_at": {
"type": "string",
"format": "date-time"
},
"last_login_at": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"required": [
"id",
"email",
"name",
"avatar_url",
"provider",
"provider_id",
"created_at",
"updated_at",
"last_login_at"
]
}

View File

@ -0,0 +1,42 @@
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
avatar_url TEXT,
provider TEXT NOT NULL,
provider_id TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_login_at TIMESTAMPTZ
);
CREATE UNIQUE INDEX IF NOT EXISTS users_provider_lookup_idx
ON users (provider, provider_id);
CREATE TABLE IF NOT EXISTS conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
title TEXT NOT NULL,
model_tag TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS conversations_user_id_idx
ON conversations (user_id);
CREATE TABLE IF NOT EXISTS messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
role TEXT NOT NULL,
content TEXT NOT NULL,
token_count INTEGER NOT NULL DEFAULT 0,
model_tag TEXT NOT NULL,
inference_time_ms INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS messages_conversation_id_idx
ON messages (conversation_id, created_at);

98
docker-compose.yml Normal file
View File

@ -0,0 +1,98 @@
services:
postgres:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB:-samosachaat}
POSTGRES_USER: ${POSTGRES_USER:-samosachaat_admin}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-localdev}
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
- ./db/migrations:/docker-entrypoint-initdb.d:ro
frontend:
build:
context: ./services/frontend
restart: unless-stopped
ports:
- "${FRONTEND_PORT:-3000}:3000"
environment:
AUTH_SERVICE_URL: ${AUTH_SERVICE_URL:-http://auth:8001}
CHAT_API_URL: ${CHAT_API_URL:-http://chat-api:8002}
NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000}
depends_on:
- auth
- chat-api
auth:
build:
context: ./services/auth
restart: unless-stopped
ports:
- "${AUTH_PORT:-8001}:8001"
environment:
DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://samosachaat_admin:localdev@postgres:5432/samosachaat}
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}
GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}
JWT_PRIVATE_KEY: ${JWT_PRIVATE_KEY:-}
JWT_PUBLIC_KEY: ${JWT_PUBLIC_KEY:-}
depends_on:
- postgres
chat-api:
build:
context: ./services/chat-api
restart: unless-stopped
ports:
- "${CHAT_API_PORT:-8002}:8002"
environment:
DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://samosachaat_admin:localdev@postgres:5432/samosachaat}
AUTH_SERVICE_URL: ${AUTH_SERVICE_URL:-http://auth:8001}
INFERENCE_SERVICE_URL: ${INFERENCE_SERVICE_URL:-http://inference:8003}
INTERNAL_API_KEY: ${INTERNAL_API_KEY:-}
depends_on:
- postgres
- auth
- inference
inference:
build:
context: ./services/inference
restart: unless-stopped
ports:
- "${INFERENCE_PORT:-8003}:8003"
environment:
MODEL_STORAGE_PATH: /models
DEFAULT_MODEL_TAG: ${DEFAULT_MODEL_TAG:-samosachaat-d12}
NANOCHAT_DTYPE: ${NANOCHAT_DTYPE:-float32}
HF_TOKEN: ${HF_TOKEN:-}
INTERNAL_API_KEY: ${INTERNAL_API_KEY:-}
NUM_WORKERS: ${NUM_WORKERS:-1}
volumes:
- ./models:/models
grafana:
image: grafana/grafana:latest
restart: unless-stopped
ports:
- "${GRAFANA_PORT:-3001}:3000"
prometheus:
image: prom/prometheus:latest
restart: unless-stopped
ports:
- "${PROMETHEUS_PORT:-9090}:9090"
loki:
image: grafana/loki:latest
restart: unless-stopped
command: -config.file=/etc/loki/local-config.yaml
ports:
- "${LOKI_PORT:-3100}:3100"
volumes:
pgdata:

4
helm/README.md Normal file
View File

@ -0,0 +1,4 @@
# Helm Charts
This directory holds Kubernetes deployment charts for the samosaChaat platform
and its supporting observability stack.

View File

@ -0,0 +1,6 @@
apiVersion: v2
name: observability
description: Observability chart scaffold for Grafana, Prometheus, and Loki.
type: application
version: 0.1.0
appVersion: "0.1.0"

View File

@ -0,0 +1,4 @@
The observability chart scaffold is in place.
Add concrete manifests for Grafana, Prometheus, Loki, dashboards, and scrape
configuration as the platform monitoring stack is implemented.

View File

@ -0,0 +1,8 @@
grafana:
enabled: true
prometheus:
enabled: true
loki:
enabled: true

View File

@ -0,0 +1,6 @@
apiVersion: v2
name: samosachaat
description: Application chart scaffold for the samosaChaat platform.
type: application
version: 0.1.0
appVersion: "0.1.0"

View File

@ -0,0 +1,4 @@
The samosaChaat application chart is scaffolded.
Populate this chart with Deployments, Services, Ingress, Secrets, and ConfigMaps
as the platform services are implemented.

View File

@ -0,0 +1,10 @@
image:
repository: ghcr.io/manmohan659/nanochat/frontend
tag: latest
pullPolicy: IfNotPresent
replicaCount: 1
service:
type: ClusterIP
port: 3000

12
scripts/local-dev.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ENV_FILE="${ROOT_DIR}/.env"
if [[ ! -f "${ENV_FILE}" ]]; then
ENV_FILE="${ROOT_DIR}/.env.example"
echo "Using ${ENV_FILE} because .env is not present."
fi
exec docker compose --env-file "${ENV_FILE}" up --build "$@"

65
scripts/seed-db.sh Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ENV_FILE="${ROOT_DIR}/.env"
if [[ ! -f "${ENV_FILE}" ]]; then
ENV_FILE="${ROOT_DIR}/.env.example"
fi
set -a
source "${ENV_FILE}"
set +a
docker compose exec -T postgres psql \
-U "${POSTGRES_USER:-samosachaat_admin}" \
-d "${POSTGRES_DB:-samosachaat}" <<'SQL'
INSERT INTO users (
id,
email,
name,
avatar_url,
provider,
provider_id,
last_login_at
) VALUES (
'11111111-1111-1111-1111-111111111111',
'demo@samosachaat.local',
'Demo User',
'https://example.com/avatar.png',
'github',
'demo-user',
NOW()
) ON CONFLICT (id) DO NOTHING;
INSERT INTO conversations (
id,
user_id,
title,
model_tag
) VALUES (
'22222222-2222-2222-2222-222222222222',
'11111111-1111-1111-1111-111111111111',
'Welcome to samosaChaat',
'samosachaat-d12'
) ON CONFLICT (id) DO NOTHING;
INSERT INTO messages (
id,
conversation_id,
role,
content,
token_count,
model_tag,
inference_time_ms
) VALUES (
'33333333-3333-3333-3333-333333333333',
'22222222-2222-2222-2222-222222222222',
'assistant',
'The database scaffold is ready for local development.',
9,
'samosachaat-d12',
12
) ON CONFLICT (id) DO NOTHING;
SQL

9
services/auth/Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM python:3.12-slim
WORKDIR /app
COPY README.md /app/README.md
EXPOSE 8001
CMD ["python", "-m", "http.server", "8001", "--bind", "0.0.0.0"]

7
services/auth/README.md Normal file
View File

@ -0,0 +1,7 @@
# Auth Service
Scaffold placeholder for Issue #5.
The monorepo branch provisions this directory and a minimal Docker image so
local `docker compose up` remains viable before the real auth service
implementation lands.

View File

@ -0,0 +1,9 @@
FROM python:3.12-slim
WORKDIR /app
COPY README.md /app/README.md
EXPOSE 8002
CMD ["python", "-m", "http.server", "8002", "--bind", "0.0.0.0"]

View File

@ -0,0 +1,7 @@
# Chat API Service
Scaffold placeholder for Issue #6.
This container is intentionally minimal on the monorepo scaffold branch. It
keeps the compose topology stable while the dedicated chat API implementation
is developed.

View File

@ -0,0 +1,9 @@
FROM python:3.12-slim
WORKDIR /app
COPY index.html /app/index.html
EXPOSE 3000
CMD ["python", "-m", "http.server", "3000", "--bind", "0.0.0.0"]

View File

@ -0,0 +1,65 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>samosaChaat frontend scaffold</title>
<style>
:root {
color-scheme: light;
font-family: "Avenir Next", "Segoe UI", sans-serif;
background: #fff7ef;
color: #26170d;
}
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background:
radial-gradient(circle at top left, rgba(255, 190, 92, 0.35), transparent 35%),
radial-gradient(circle at bottom right, rgba(226, 107, 74, 0.18), transparent 32%),
#fff7ef;
}
main {
width: min(720px, calc(100vw - 3rem));
padding: 2rem;
border-radius: 24px;
background: rgba(255, 255, 255, 0.85);
box-shadow: 0 24px 60px rgba(84, 44, 22, 0.12);
}
h1 {
margin-top: 0;
font-size: clamp(2rem, 5vw, 3rem);
}
p,
li {
line-height: 1.6;
}
code {
background: #fff1df;
padding: 0.15rem 0.4rem;
border-radius: 8px;
}
</style>
</head>
<body>
<main>
<h1>samosaChaat platform scaffold</h1>
<p>
The monorepo structure is in place. This placeholder frontend keeps
<code>docker compose up</code> usable until the real UI lands.
</p>
<ul>
<li>Auth service: <code>http://localhost:8001</code></li>
<li>Chat API: <code>http://localhost:8002</code></li>
<li>Inference: <code>http://localhost:8003</code></li>
</ul>
</main>
</body>
</html>

View File

@ -0,0 +1,9 @@
FROM python:3.12-slim
WORKDIR /app
COPY README.md /app/README.md
EXPOSE 8003
CMD ["python", "-m", "http.server", "8003", "--bind", "0.0.0.0"]

View File

@ -0,0 +1,6 @@
# Inference Service
Scaffold placeholder for Issue #3.
This branch only creates the monorepo structure. The next branch extracts the
FastAPI inference microservice into this directory.

6
terraform/README.md Normal file
View File

@ -0,0 +1,6 @@
# Terraform
Environment and module scaffolding for the samosaChaat AWS platform.
- `environments/` holds per-environment stacks for `dev`, `uat`, and `prod`
- `modules/` holds reusable building blocks for shared infrastructure

View File

@ -0,0 +1,6 @@
# dev
Development environment stack scaffold.
Use this directory to wire together the shared Terraform modules for the dev
AWS account and domain configuration.

View File

@ -0,0 +1,6 @@
# prod
Production environment stack scaffold.
Use this directory to compose the shared Terraform modules with production
networking, security, and availability requirements.

View File

@ -0,0 +1,6 @@
# uat
User acceptance testing environment stack scaffold.
Use this directory to compose the shared Terraform modules with UAT-specific
variables, state backends, and deployment topology.

View File

@ -0,0 +1,3 @@
# acm module
Scaffold placeholder for the shared ACM certificate module.

View File

@ -0,0 +1,3 @@
# ecr module
Scaffold placeholder for the shared container registry module.

View File

@ -0,0 +1,3 @@
# efs module
Scaffold placeholder for the shared EFS storage module.

View File

@ -0,0 +1,3 @@
# eks module
Scaffold placeholder for the shared EKS cluster module.

View File

@ -0,0 +1,3 @@
# iam module
Scaffold placeholder for the shared IAM roles and policy module.

View File

@ -0,0 +1,3 @@
# rds module
Scaffold placeholder for the shared PostgreSQL / RDS module.

View File

@ -0,0 +1,3 @@
# route53 module
Scaffold placeholder for the shared DNS management module.

View File

@ -0,0 +1,3 @@
# vpc module
Scaffold placeholder for the shared VPC networking module.