Where it is going
Maturity phases
Generated from ROADMAP.md in the AstroBaaS repository. The repository is the source of truth; this page is a copy of it.
This document is a pragmatic, phased plan to take the repo from “prototype” to “alpha-usable”. Each phase is small enough to ship in one PR and leaves the app in a working state. Earlier phases are blockers for later ones.
Progress against this plan is recorded in CHANGELOG.md. The
extensibility surface for theme/plugin authors — and what’s deferred past alpha
— is documented in PLATFORM.md and STABILITY.md.
Guiding principles
- Server-only secrets. Anything sensitive (sessions, password hashes, upload writes) must run server-side. The admin UI is JS-light; rely on regular HTML form posts where possible.
- One source of truth. Today: LowDB (
db.json). The Supabase code is a half-finished alternative path — we cut it (Phase 1) rather than maintain both. - Boring tech first. No JWTs, no Redis, no message bus. A signed cookie + in-memory rate-limit is enough for alpha.
- Working > complete. A feature flag is preferable to a half-broken page.
Phase 0 — Repo hygiene (≈ 30 min)
Goal: a clean baseline.
- Remove
dist/from the working tree (it’s in.gitignorealready). - Remove
db.jsonfrom version control. Shipdb.seed.jsonas a template and copy on first run. - Remove the unused Supabase client/types/migrations (
src/lib/supabase.ts,src/lib/database.types.ts,supabase/). - Delete
src/pages/admin/posts/test.astro(debug scratch). - Add
npm run typecheckscript.
Done when: git status is clean after npm run build.
Phase 1 — Authentication & security foundations (this PR)
Goal: nobody can hit admin/API without logging in.
- Session store: signed-cookie sessions (HMAC-SHA256 with
AUTH_SECRET). No third-party deps; small helper insrc/lib/auth.ts. - Password hashing: PBKDF2 from
node:crypto(no native bcrypt build). Addpassword_hashandpassword_saltcolumns to theUsertype and a seeded admin (admin@local/admin) on first boot. /login,/logoutAstro pages +POST /api/auth/login,/api/auth/logout.- Middleware (
src/middleware.ts):- Reads the session cookie, attaches
locals.user. - Blocks unauthenticated requests to
/admin/*and write methods on/api/*(everything except whitelisted public GETs). - Adds security headers:
X-Frame-Options DENY,X-Content-Type-Options nosniff,Referrer-Policy strict-origin-when-cross-origin, a starter CSP, andPermissions-Policy. - Adds a per-IP in-memory rate-limit on
/api/*(60 req / min). - Issues a CSRF token cookie + verifies it on non-GET API calls.
- Reads the session cookie, attaches
- Wire the AdminHeader sign-out button to
POST /api/auth/logout.
Done when: logged-out user hitting /admin is redirected to /login;
API write calls without a valid session return 401.
Phase 2 — API hardening (next)
- Standardize on
ApiResponseBuildereverywhere (kill ad-hoc shapes). - Introduce a tiny validator (
src/lib/validate.ts) — no zod dep needed for alpha; a typed schema helper is plenty. - Convert non-RESTful routes:
POST /api/posts/create→POST /api/postsPUT /api/posts/update→PUT /api/posts/[id]DELETE /api/posts/delete→DELETE /api/posts/[id]- same for categories, users, media. Keep thin re-export shims at the old paths for one release.
- Fix
content/changes: align positional args, use ISO stringsince. - Sanitize HTML on input (DOMPurify equivalent on the server — small allow-list sanitizer is fine for alpha).
Done when: every endpoint returns { success, data | error }, requires
auth for writes, and rejects malformed bodies with 422.
Phase 3 — Content model maturity
- Pages as a first-class type (alongside posts) so
/about,/contactcome out of the DB instead of being hard-coded.astrofiles. - Slug auto-generation + uniqueness check at create time.
- Status workflow:
draft → review → scheduled → published → trashed. - Tags as their own collection (currently a string[] on Post).
- Post revisions: append-only
post_revisionstable, capped at N per post. - Search endpoint:
GET /api/search?q=…over title + content (LIKE for now).
Phase 4 — Media & uploads (make uploads real)
- Persist files to
public/uploads/yyyy/mm/<hash>.<ext>on POST. - MIME-type allow-list + size limit (10 MB default).
- Compute width/height for images, store on the MediaFile record.
DELETE /api/media/[id]removes the row and the file.- Use the AlertText helper to display per-file upload errors.
Phase 5 — Public site polish
/sitemap.xml(SSR endpoint reading posts + pages)./rss.xmlfor posts.- Real OG image fallback (site setting
og_image). - Inject theme CSS variables in
BaseLayoutserver-side (drop the fetch-on-load roundtrip that flashes default colors). - 404 page (
src/pages/404.astro). - Robots.txt.
Phase 6 — Admin UX
- Real dashboard stats (count posts/users/media; recent activity from
contentChanges). - Pagination + search on
/admin/posts. - Bulk actions: delete, publish, change category.
- Working user-menu profile + preferences pages.
- Toast notifications on every mutating action.
Phase 7 — Observability & DX
- Structured request log (one line per request, JSON).
- Error boundary page + a single
reportError()shim. npm testrunning a smoke test that boots the dev server and hits the public + admin routes.- CI workflow (
.github/workflows/ci.yml) runningtypecheck,build, and the smoke test.
Phase 8 — BaaS / headless (landed)
Phases 0–7 delivered the secure CMS. Phase 8 turned it into a backend a separate frontend or an AI agent can use. All of the following are shipped and tested (see VISION.md for the strategy and CHANGELOG.md for detail):
- A — Cross-origin access: API-key/bearer auth + configurable CORS;
agent-readable contract (
/llms.txt,/openapi.json). - B — Durable persistence: pluggable
Storagewith a libSQL/SQLite driver (DATABASE_URL); lowdb stays the local default. See STORAGE.md. - C — Effortless wiring: typed SDK
astrobaas/client, theastrobaasCLI (init/secret/setup), and theastrobaas-mcpMCP server. - D — Events: signed outbound webhooks on content lifecycle events.
See INTEGRATION.md for the usage guide.
Open follow-ups (post-alpha)
The full, themed, prioritized list lives in BACKLOG.md. The headline items:
- Packaging for external use — the public
exportspoint at TS source; ship built.js/.d.ts+ publish to npm so non-Vite consumers can install it. - Relational storage driver ✅ shipped (
DATABASE_DRIVER=relational, per-entity rows). Remaining: a fully-normalized column schema + an optional Postgres adapter. - Webhook delivery durability — retry/backoff + a delivery log (today: fire-and-forget, 5s timeout, no retry).
- Realtime subscriptions — push (SSE/WebSocket) instead of webhook polling.
- Shared rate-limiter for multi-replica deploys (today: in-process).
- Hosted option / one-click templates for the no-VPS audience.
Out of scope for alpha
- Multi-site, i18n, e-commerce, GraphQL, WebSocket live preview.
- A formal plugin marketplace.
- A separate background-job worker. Scheduled posts can be a request-time check in alpha.
These are valuable but each is bigger than the rest of alpha combined.