Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Project Templates

A collection of project templates for different languages and frameworks.
Functionality and structure will vary depending on the template — see the README.md inside each template folder (e.g., go/, python-django/) for specific details.

All templates are built from scratch using patterns that have worked well for me in real-world projects.
Feel free to use, adapt, and extend them — enjoy! 🚀

Quick comparison

Aspect Go Version Django Version
Language Go Python
Entrypoint Compiled binary (pk_projName) manage.py (CLI runner)
DB Handling SQLC + raw Django ORM + migrations
e2e API Test Runner *noCRUD (python) *noCRUD (python)
Build style Binary compilation Source + pip install
Runtime Debian + single binary Debian + Python runtime

noCRUD

Basic Structure

I keep the same basic structure for all my applications: the frontend is static and served by CloudFront, the backend runs in containers on a box. The frontend is never containerized and never runs on the server.

                          Route 53
              /                          \
   domain.com                             api.domain.com
        |                                       |
        v                                       v
  +------------+                     +------------------------+
  | CloudFront |                     | The box (VPS/EC2)      |
  +------------+                     |  +------------------+  |
        |                            |  | Traefik          |  |
        v                            |  |  (TLS, routing)  |  |
  +------------+                     |  +--------+---------+  |
  | S3 bucket  |                     |           |            |
  | static SPA |                     |           v            |
  | build      |                     |  +------------------+  |
  +------------+                     |  | Backend          |  |
                                     |  | Go / Django      |  |
   built on the dev machine,         |  +------------------+  |
   pushed by deploy_frontend.sh      |  | Prometheus       |  |
                                     |  | Grafana          |  |
        the SPA calls                |  +------------------+  |
   https://api.domain.com  --------> +------------------------+
                                              |
                                              v
                                        Postgres (RDS)

Two independent deploys, two scripts:

What Script Target
Static SPA build deploy_frontend.sh S3 + CloudFront invalidation
Backend + Traefik + Prometheus + Grafana deploy.sh The box, via scp + compose

Because the two live on different origins, every API call from the browser is cross-origin. That means FRONTEND_ORIGIN (in ~/env_setup/<project>/prod_backend.sh) must be set to the CloudFront origin — it feeds the backend's CORS allowlist. If API calls 403/fail preflight, check that first.

Do After Generation (and backend setup found in backend readme.md)

  • Create a frontend with the quasar CLI
    • Install the CLI: npm i -g @quasar/cli
    • cd to /frontend
    • npm init quasar@latest
      • use . to keep it directly in the frontend
  • Run the frontend locally with its dev server (npm run dev), pointed at http://localhost:4500
  • Test the local backend stack with build_and_deploy_local.sh / verify_docker_builds.sh

Deployment (Prod)

Frontend — S3 + CloudFront

One-time AWS setup (console or CLI, not scripted here):

  • Private S3 bucket, no static website hosting — CloudFront reads it via OAC
  • CloudFront distribution with that bucket as origin, default root object index.html
  • Custom error responses: 403 and 404 → /index.html with status 200 (SPA history mode)
  • ACM cert in us-east-1 for the apex, attached to the distribution
  • Route 53 A/AAAA alias records for the apex → the distribution

Then set BUCKET and DISTRIBUTION_ID at the top of deploy_frontend.sh and run it. It builds, syncs with split cache headers (hashed assets immutable, index.html no-cache), and invalidates.

Backend — containers on the box

Current process is build the backend container locally (with prod settings) and copy to server.

  • Remember to backup RDS and migrate(update db schema)!! Prod DB operations are not handled by deploy.sh

This is all in deploy.sh.. but here is the general process. Look to the backend readme for deep guidance on its container.

Step 1 - On Dev Machine

docker build -f ./backend/Dockerfile -t backend:latest ./backend

docker save -o backend.tar backend:latest

scp backend.tar user@server:/deploypath/
scp compose_deploy.yaml user@server:/deploypath/

Step 2 - On Server

docker load < /deploypath/backend.tar
# Note: Ensure the compose file has the correct reference to the container

#check to see the images
docker images

# Start the containers!
docker compose up -d #detached (run in background, return control to terminal)

All about the uris...

Routing is split by subdomain, not by path prefix:

  1. domain.com is Route 53 → CloudFront → S3. Traefik never sees it, and the box does not serve it.
  2. api.domain.com is Route 53 → the box → Traefik → the backend container.
  3. Because the backend owns its whole subdomain, its routes stay clean (/someEndpoint) with no /api prefix to strip and nothing environment-specific baked into the code.
  4. The frontend only needs one build-time variable — the API base URL (https://api.domain.com). Locally that is http://localhost:4500; same path shape either way.
  5. The Traefik dashboard is on api.domain.com/dashboard (behind basic auth), since the apex now belongs to CloudFront.

About

Proj template

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages