Skip to content

martinapapp/spiralSounds

Repository files navigation

Spiral Sounds

MIT License Node.js SQLite

A full-stack vinyl record store where users can browse albums, filter by genre, search by title or artist, and manage a shopping cart. link here

Index


About

Spiral Sounds is a classic vinyl record shop built as a full-stack web application. The main goal was to learn how to:

  • Build a REST API with Node.js and Express
  • Manage sessions for user authentication using express-session
  • Hash and verify passwords securely with bcryptjs
  • Work with a SQLite relational database using the sqlite and sqlite3 packages
  • Validate and sanitise user input on both the client and server
  • Structure a project with routes, controllers, and middleware separation
  • Write vanilla JavaScript ES modules on the frontend
  • Handle authenticated requests and protect routes with custom middleware
  • Build a dynamic UI that reflects auth state (greeting, menu items, cart icon)

Usage

Installation

  1. Clone the repository:

    git clone https://github.com/your-username/spiral-sounds.git
    cd spiral-sounds
  2. Install dependencies:

    npm install
  3. (Optional) Set a session secret via environment variable — otherwise a default is used:

    SPIRAL_SESSION_SECRET=your-secret-here
    

    For easy generate secret key use this code in terminal : node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

  4. Start the server:

    npm start
  5. Open your browser and go to http://localhost:8000

Commands

npm start   // Starts the Express server on port 8000

Note: This project uses plain Node.js with Express — no build step or bundler required. JS files are served as static ES modules directly from the public/ folder.


Challenges & Solutions

Session cookie not sent with fetch requests - After setting up express-session, the auth worked on login but every subsequent fetch to a protected route returned 401. The session cookie existed in the browser but wasn't being sent. The fix was adding credentials: 'include' to every fetch call that needed auth - without it the browser strips the cookie from cross-context requests by default. Also required setting sameSite: 'lax' on the session cookie to allow it through.

Static files conflicting with API routes - express.static('public') was catching requests before they reached the API routers because of middleware ordering. Moved app.use(express.static(...)) after all app.use('/api/...') registrations so API routes take priority, with static file serving as the fallback.

Cart total calculation across quantity - The cart table stores individual items with a quantity column. The total had to be computed from price × quantity per item, then summed - getting this right in both the SQL query and the frontend reduce took a few iterations to keep consistent between what the server returned and what the UI displayed.

Key Technical Decisions

Session-based auth over JWT - Sessions store auth state server-side with an httpOnly cookie, so the token is never accessible to JavaScript. For a server-rendered vanilla JS app with no separate frontend domain this is simpler and more secure than managing JWTs in localStorage.

Vanilla JS ES modules on the frontend - No bundler, no framework. Each page loads only the modules it needs (cart.js imports from cartService.js, index.js imports from productService.js). This kept the project focused on understanding the browser's native module system before reaching for build tools.

Route → controller separation - Routes define the paths and attach middleware; controllers contain the actual logic. This made it straightforward to add the requireAuth middleware to specific routes without touching the business logic.

What I'd Do Differently

  • Hash passwords with bcrypt before storing — currently passwords may be stored in plain text in the SQLite database
  • Add secure: true to the session cookie for production (requires HTTPS)
  • Replace the innerHTML approach in renderProducts and renderCartItems with DOM methods to reduce XSS risk

Development

Pre-Requisites

  • Node.js v18 or higher
  • A text editor
  • A REST client

File Structure

No File Name What it does
1 server.js Entry point — sets up Express, sessions, static files, and mounts all routers
2 db/db.js Opens and returns a SQLite database connection
3 routes/auth.js Defines routes for register, login, and logout
4 routes/cart.js Defines routes for cart operations (add, get, delete)
5 routes/products.js Defines routes for fetching products and genres
6 routes/me.js Defines route for fetching the current logged-in user
7 controllers/authController.js Handles registration, login, and logout logic
8 controllers/cartController.js Handles add, fetch, and delete cart item logic
9 controllers/productsController.js Handles product and genre queries with optional filters
10 controllers/meController.js Returns current user info from session
11 middleware/requireAuth.js Blocks unauthenticated access to protected routes
12 public/js/index.js Main script for the homepage — initialises products, auth, and events
13 public/js/cart.js Main script for the cart page
14 public/js/authUI.js Shared auth helpers: session check, greeting, menu visibility
15 public/js/cartService.js Cart API calls and DOM rendering for cart items
16 public/js/productService.js Fetches products and populates the genre dropdown
17 public/js/productUI.js Renders product cards and handles search filtering
18 public/js/login.js Handles login form submission
19 public/js/signup.js Handles signup form submission
20 public/js/logout.js Sends logout request and redirects
21 public/js/menu.js Toggles the mobile nav menu
22 public/css/index.css All styles — variables, layout, components, responsive
23 database.db SQLite database with users, products, and cart_items tables
24 logTable.js Dev utility to log any DB table to the console

Build

There is no build step. The frontend uses native ES modules loaded directly by the browser. The Express server serves all static files from the public/ folder and handles API requests under /api/.

When a user visits the site:

  1. The browser loads the HTML and its associated JS module
  2. The JS fetches data from the API (products, auth status, cart count)
  3. The DOM is updated dynamically based on the response

Authentication is session-based — on login or register, a session is created server-side and a cookie is sent to the browser. Protected routes check req.session.userId via the requireAuth middleware.


Contribution

  1. Found a bug? Open an issue and I'll try to fix it.
  2. Advice? If you have ideas for improving the store, the UI, or the API design, let me know!

License

Feel free to use this for your own practice! MIT License.

About

A full-stack vinyl record store where users can browse albums, filter by genre, search by title or artist, and manage a shopping cart.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors