A shared weblog application built with Go, Echo, PostgreSQL, and vanilla JavaScript.
Users can publish public or private entries, selectively share private posts with other users, and comment on posts they can access.
- User signup and login with JWT authentication
- Create public or private posts
- Share private posts with specific users
- Public post feed with title search and pagination
- Comments on accessible posts
- Delete your own posts and comments
- Image upload with size and type validation
- Protected routes for authenticated actions
| Layer | Technology |
|---|---|
| Backend | Go 1.26, Echo v5 |
| Database | PostgreSQL, pgx |
| Migrations | golang-migrate |
| Authentication | JWT, bcrypt |
| Configuration | cleanenv, godotenv |
| Frontend | HTML, CSS, Vanilla JavaScript |
- Go 1.26+
- Docker (recommended) or a local PostgreSQL installation
git clone git@github.com:kiarash86/Marginalia.git
cd MarginaliaCreate a .env file in the project root:
DATABASE_URL=postgres://postgres:postgres@localhost:5432/weblog?sslmode=disable
JWT_KEY=change-this-secret
PORT=8080Use a strong secret for
JWT_KEYin any non-local environment.
Using Docker:
docker-compose up -dThis starts PostgreSQL 16 on localhost:5432 with the weblog database.
go run main.goDatabase migrations run automatically on startup.
The API will be available at:
http://localhost:8080
The frontend is a static HTML/CSS/JavaScript application.
Update frontend/config.js if needed:
window.MARGINALIA_CONFIG = {
API_BASE: 'http://localhost:8080'
};Then serve the frontend directory with any static file server, for example:
npx serve frontendAll protected routes require an Authorization: Bearer <token> header.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /health |
— | Health check |
| POST | /signup |
— | Create an account |
| POST | /login |
— | Log in |
| GET | /weblog |
Yes | Feed with pagination and title search |
| POST | /weblog |
Yes | Create a post |
| GET | /weblog/:id |
Yes | Get a single accessible post |
| DELETE | /weblog/:id |
Yes | Delete an owned post |
| POST | /weblog/:id/share |
Yes | Share a private post |
| GET | /weblog/:id/comment |
Yes | List comments |
| POST | /weblog/:id/comment |
Yes | Add a comment |
| DELETE | /weblog/:id/comment/:commentId |
Yes | Delete an authored comment |
| POST | /upload |
Yes | Upload an image (max 5 MB) |
| GET | /uploads/* |
— | Serve uploaded images |
.
├── main.go
├── internal/
│ ├── auth/
│ ├── config/
│ ├── db/
│ ├── handlers/
│ ├── middlewares/
│ ├── migration/
│ ├── models/
│ └── repository/
├── frontend/
├── Dockerfile
└── docker-compose.yml
- Posts cannot be edited; they must be deleted and recreated. This follows the original assignment requirements.
- No email verification or password reset flow.
- Upload validation currently checks file extensions rather than file contents, so it is not hardened for adversarial input.
- No automated test suite is included yet.
This project is provided for educational and portfolio purposes.