Skip to content

Commit 4472a40

Browse files
committed
Restructure project layout for migration
1 parent 7391f4f commit 4472a40

File tree

10 files changed

+320
-9
lines changed

10 files changed

+320
-9
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ dist/
88
*.db
99
*.env
1010
*.flaskenv
11+
frontend/node_modules/
12+
frontend/dist/

.plans/fastapi-railway-ts-mvp.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# [ ] MVP Migration Plan: FastAPI on Railway + TypeScript Frontend on GitHub Pages
2+
3+
## [ ] Summary
4+
- [ ] Build FastAPI backend on Railway using existing Python game logic
5+
- [ ] Build React + TypeScript frontend on GitHub Pages
6+
- [ ] Persist anonymous sessions in Railway Postgres via browser-stored UUID
7+
8+
## [ ] Architecture Decisions (Locked)
9+
- [ ] Frontend stack: `Vite + React + TypeScript`
10+
- [ ] Session model: anonymous UUID stored in browser `localStorage`
11+
- [ ] Session persistence: Railway Postgres
12+
- [ ] API transition: clean API now under `/api/v1/*` (no Hug compatibility paths)
13+
14+
## [ ] Public API / Interface Changes
15+
16+
### [ ] Backend HTTP API (new)
17+
- [ ] `GET /api/v1/health` -> `{ "status": "ok" }`
18+
- [ ] `POST /api/v1/session` -> create/validate session
19+
- [ ] `POST /api/v1/command` -> execute command and persist state
20+
- [ ] `POST /api/v1/session/reset` -> clear state for session
21+
22+
### [ ] TypeScript Frontend Types (new)
23+
- [ ] `SessionCreateRequest`, `SessionCreateResponse`
24+
- [ ] `CommandRequest`, `CommandResponse`
25+
- [ ] `ApiError` with stable `code` + `message`
26+
- [ ] Runtime API response validation (e.g. Zod)
27+
28+
### [ ] Persistence Contract
29+
- [ ] Create `adventure_sessions` table
30+
- [ ] Fields: `session_id`, `save_data`, `created_at`, `updated_at`
31+
32+
## [x] Phase 0: Repo Restructure + Guardrails (Day 1)
33+
- [x] Create `backend/` and `frontend/` directories
34+
- [x] Keep `adventure/` reusable by backend
35+
- [x] Add architecture + local dev quickstart docs
36+
- [x] Standardize env vars (`DATABASE_URL`, `CORS_ALLOW_ORIGINS`, `VITE_API_BASE_URL`)
37+
- [x] Add `CONTRIBUTING.md` for backend/frontend workflows
38+
39+
### [x] Exit Criteria
40+
- [x] Monorepo layout documented
41+
- [x] README has exact run instructions for both apps
42+
43+
## [ ] Phase 1: FastAPI Adapter over Existing Engine (Day 1-2)
44+
- [ ] Create FastAPI app with startup DB init + CORS + Pydantic models
45+
- [ ] Implement service flow: load session -> optional `admin_load` -> execute -> `admin_save`
46+
- [ ] Implement `/health`, `/session`, `/command`, `/session/reset`
47+
- [ ] Preserve current markdown-to-HTML response behavior
48+
49+
### [ ] Exit Criteria
50+
- [ ] Manual API flow works end-to-end
51+
- [ ] Command response parity with current Hug behavior
52+
53+
## [ ] Phase 2: Postgres Persistence (Day 2)
54+
- [ ] Add SQLAlchemy 2.0 + Alembic in backend
55+
- [ ] Create initial migration for `adventure_sessions`
56+
- [ ] Add `SessionRepository` abstraction
57+
- [ ] Implement `PostgresSessionRepository`
58+
- [ ] Ensure idempotent session create/get semantics
59+
60+
### [ ] Exit Criteria
61+
- [ ] Fresh DB migration succeeds
62+
- [ ] Save/load survives app restart
63+
- [ ] Reset endpoint clears state correctly
64+
65+
## [ ] Phase 3: TS Frontend MVP (Day 2-3)
66+
- [ ] Create React UI: transcript, input, status/error, reset/new game
67+
- [ ] Implement session bootstrap from `localStorage`
68+
- [ ] Implement command send/receive flow with loading states
69+
- [ ] Configure `VITE_API_BASE_URL` for environment-specific backend URL
70+
- [ ] Ensure production build works for GitHub Pages
71+
72+
### [ ] Exit Criteria
73+
- [ ] App playable from GitHub Pages
74+
- [ ] Refresh resumes session
75+
- [ ] Reset starts a fresh session
76+
77+
## [ ] Phase 4: Deployments + CI/CD (Day 3-4)
78+
- [ ] Deploy backend service to Railway
79+
- [ ] Attach Railway Postgres plugin
80+
- [ ] Configure backend env vars and health check
81+
- [ ] Configure GitHub Action to build/deploy frontend to Pages
82+
- [ ] Configure production CORS for GitHub Pages origin(s)
83+
84+
### [ ] Exit Criteria
85+
- [ ] Railway API healthy
86+
- [ ] GitHub Pages deployed successfully
87+
- [ ] Frontend can call production API without CORS errors
88+
89+
## [ ] Phase 5: Quality, Tests, Contributor UX (Day 4-5)
90+
- [ ] Backend route tests (`health/session/command/reset`)
91+
- [ ] Backend service + persistence tests
92+
- [ ] Frontend API + UI behavior tests
93+
- [ ] End-to-end smoke test for play/resume/reset
94+
- [ ] Add contributor docs for extending content and commands
95+
96+
### [ ] Exit Criteria
97+
- [ ] CI green for backend + frontend
98+
- [ ] New contributor can run project in <10 minutes from docs
99+
100+
## [ ] Data-Driven Expandability (MVP-Compatible Staging)
101+
- [ ] Keep existing Python engine for MVP
102+
- [ ] Define `content/` contract for locations/items/commands metadata
103+
- [ ] Keep parser/engine in code for now
104+
- [ ] Plan post-MVP migration of content into validated data files
105+
- [ ] Add command registry pattern for future plugin-style expansion
106+
107+
## [ ] Testing Scenarios and Acceptance Criteria
108+
109+
### [ ] Core gameplay/session
110+
- [ ] New browser session starts correctly
111+
- [ ] Command execution returns expected HTML output
112+
- [ ] Refresh resumes session state
113+
- [ ] Reset clears state
114+
- [ ] Invalid/empty input returns stable error
115+
116+
### [ ] Reliability
117+
- [ ] Session survives backend restart
118+
- [ ] Unknown `session_id` handled by create-on-demand policy
119+
- [ ] DB outage returns structured 5xx response
120+
121+
### [ ] Deployment
122+
- [ ] GitHub Pages deploy on main succeeds
123+
- [ ] Railway deploy succeeds and health check passes
124+
- [ ] Production supports multi-command gameplay flow
125+
126+
## [ ] Risks and Mitigations
127+
- [ ] Session schema drift -> add session versioning + migrations
128+
- [ ] Markdown rendering drift -> snapshot parity tests
129+
- [ ] CORS issues -> explicit allowed-origins env + integration check
130+
131+
## [ ] Assumptions and Defaults
132+
- [ ] No auth/login in MVP
133+
- [ ] One local session token per browser
134+
- [ ] Backend is API-only (no server-rendered pages)
135+
- [ ] Python engine retained for MVP timeline
136+
- [ ] Postgres is source of truth for saves
137+
- [ ] Full data-driven engine evolution happens post-MVP

CONTRIBUTING.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Contributing
2+
3+
## Development Workflow (Phase 0)
4+
5+
This repository is in a staged migration from Hug to FastAPI + TypeScript frontend.
6+
7+
### Prerequisites
8+
9+
- Python 3.10+
10+
- `uv`
11+
- Node.js 20+ (for frontend phase)
12+
13+
### Install Python dependencies
14+
15+
```sh
16+
uv sync --all-groups
17+
```
18+
19+
### Current runnable app (legacy Hug)
20+
21+
```sh
22+
uv run hug -m web.app
23+
```
24+
25+
### New app directories
26+
27+
- `backend/`: FastAPI service scaffold (implementation begins in Phase 1).
28+
- `frontend/`: TypeScript frontend scaffold (implementation begins in Phase 3).
29+
30+
## Environment Setup
31+
32+
Copy and adjust env templates as needed:
33+
34+
- `backend/.env.example`
35+
- `frontend/.env.example`
36+
37+
## Testing
38+
39+
Current tests (legacy app):
40+
41+
```sh
42+
uv run pytest
43+
```

README.md

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,59 @@ Two easy ways to launch the console project:
2626

2727
NOTE: the MacOS version does not have code signing built into it yet (that's next on my list!). To run it, you will need to set the binary as executable with `chmod 755` or similar, and after trying to run it once, go through System Preferences: Security and Privacy: General and "Allow the program to run anyway".
2828

29-
## Web (Hug) version
29+
## Monorepo Layout (Phase 0)
3030

31-
* Install [Python](https://www.python.org) 3.10 or higher
32-
* Install [uv](https://docs.astral.sh/uv/)
33-
* At a command prompt in the project directory, type `uv sync --all-groups` to set up dependencies
31+
- `adventure/`: shared game engine logic
32+
- `backend/`: FastAPI service scaffold (target Railway deploy)
33+
- `frontend/`: TypeScript frontend scaffold (target GitHub Pages deploy)
34+
- `web/`: current legacy Hug web app
35+
- `docs/architecture.md`: migration architecture notes
3436

35-
Next. set the flask application environment variables:
37+
## Local Development Quickstart
38+
39+
Install tooling and Python dependencies:
40+
41+
- Install [Python](https://www.python.org) 3.10+
42+
- Install [uv](https://docs.astral.sh/uv/)
43+
- Run `uv sync --all-groups` from repo root
44+
45+
Standardized environment variables:
46+
47+
- Backend: `DATABASE_URL`, `CORS_ALLOW_ORIGINS` (see `backend/.env.example`)
48+
- Frontend: `VITE_API_BASE_URL` (see `frontend/.env.example`)
49+
50+
### Run Backend (Current Legacy App)
51+
52+
```sh
53+
uv run hug -m web.app
54+
```
55+
56+
Navigate to [http://localhost:8000/](http://localhost:8000/)
57+
58+
### Run Frontend (Phase 0 Placeholder)
59+
60+
```sh
61+
cd frontend
62+
python -m http.server 5173
63+
```
64+
65+
Navigate to [http://localhost:5173/](http://localhost:5173/)
66+
67+
## Legacy Hug Notes
3668

3769
The easiest option is to create a `.env` file in the root of the project with the contents:
3870

3971
```config
4072
SECRET_KEY="<some random key>"
4173
```
4274

43-
alternatively, you can manually set your environment variables for your terminal session but you'll have to remember to do that for every new session.
75+
Alternatively, you can manually set your environment variables for your terminal session, but you'll have to remember to do that for every new session.
4476

4577
```sh
46-
EXPORT SECRET_KEY="<put something random here>"
78+
export SECRET_KEY="<put something random here>"
4779
```
4880

49-
### Running the development web server
81+
### Running the legacy development web server
5082

5183
In the root of the project, run:
5284

@@ -58,7 +90,7 @@ Navigate in your browser to:
5890

5991
[http://localhost:8000/](http://localhost:8000/)
6092

61-
Have Fun!
93+
Have fun!
6294

6395
If you want to restart delete your `sid` cookie from your browser and refresh the page.
6496

backend/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/zorkdemo
2+
CORS_ALLOW_ORIGINS=http://localhost:5173,https://bcorfman.github.io

backend/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Backend (Phase 0 Scaffold)
2+
3+
This directory is reserved for the FastAPI backend service that will run on Railway.
4+
5+
## Status
6+
7+
Phase 0 scaffold only. The production backend logic is still in the legacy `web/` package until Phase 1 migration is complete.
8+
9+
## Environment Variables (Standardized)
10+
11+
- `DATABASE_URL`: Postgres connection string for session persistence.
12+
- `CORS_ALLOW_ORIGINS`: Comma-separated allowed origins (for example, GitHub Pages URL + localhost).
13+
14+
## Planned Run Command (Phase 1+)
15+
16+
```sh
17+
uv run uvicorn backend.app.main:app --host 0.0.0.0 --port 8000 --reload
18+
```

docs/architecture.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Architecture (MVP Target)
2+
3+
## Monorepo Layout
4+
5+
- `adventure/`: existing game engine logic (shared by backend during MVP).
6+
- `backend/`: FastAPI service for API and session persistence.
7+
- `frontend/`: TypeScript browser client (GitHub Pages).
8+
- `web/`: legacy Hug implementation (to be retired after migration).
9+
- `.plans/`: migration plans and checklists.
10+
11+
## Runtime Topology
12+
13+
- Frontend is static and served by GitHub Pages.
14+
- Frontend calls backend HTTP API on Railway.
15+
- Backend persists session save blobs in Postgres.
16+
17+
## Environment Variables
18+
19+
### Backend
20+
21+
- `DATABASE_URL`
22+
- `CORS_ALLOW_ORIGINS`
23+
24+
### Frontend
25+
26+
- `VITE_API_BASE_URL`

frontend/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
VITE_API_BASE_URL=http://localhost:8000

frontend/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Frontend (Phase 0 Scaffold)
2+
3+
This directory is reserved for the browser frontend that will be deployed to GitHub Pages.
4+
5+
## Status
6+
7+
Phase 0 scaffold only. The TypeScript app is created during Phase 3.
8+
9+
## Environment Variables (Standardized)
10+
11+
- `VITE_API_BASE_URL`: FastAPI backend base URL.
12+
13+
## Planned Run Commands (Phase 3+)
14+
15+
```sh
16+
npm install
17+
npm run dev
18+
```

frontend/index.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>ZorkDemo Frontend Scaffold</title>
7+
<style>
8+
body {
9+
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
10+
max-width: 720px;
11+
margin: 3rem auto;
12+
padding: 0 1rem;
13+
line-height: 1.5;
14+
}
15+
code {
16+
background: #f2f2f2;
17+
padding: 0.1rem 0.3rem;
18+
border-radius: 0.25rem;
19+
}
20+
</style>
21+
</head>
22+
<body>
23+
<h1>ZorkDemo Frontend Scaffold</h1>
24+
<p>
25+
This is the Phase 0 placeholder for the future React + TypeScript frontend.
26+
</p>
27+
<p>
28+
Configure backend URL with <code>VITE_API_BASE_URL</code> in
29+
<code>frontend/.env.example</code> when the app is initialized in Phase 3.
30+
</p>
31+
</body>
32+
</html>

0 commit comments

Comments
 (0)