= SPEC-1: Open Source Information and Products for Marijuana Users
:sectnums:
:toc:
== Background
The increasing legalization and acceptance of marijuana use has created a demand for reliable information and product listings tailored for marijuana users. This application aims to be an open-source resource that provides comprehensive information on marijuana strains, effects, legal guidelines, and related products.
== Requirements
*Must Have*:
- Information on various marijuana strains, including effects and medical uses
- Listings of related products (e.g., accessories, seeds, edibles)
- User authentication and profiles
- Search functionality
- User reviews and ratings
*Should Have*:
- Legal information by region
- User-generated content and contributions
- Mobile responsiveness
*Could Have*:
- E-commerce capabilities for purchasing products
- Real-time chat or community features
*Won't Have*:
- Advanced analytics and reporting in the initial version
== Method
The application will be developed using the following technologies:
- **Frontend**: React.js for building the user interface
- **Backend**: Node.js with Express.js for the server
- **Database**: MongoDB for storing user data, product information, and reviews
The architecture will follow a RESTful API design, with separate frontend and backend services. User authentication will be handled using JWT (JSON Web Tokens).
== Implementation
1. **Setup the project structure**:
- Create a new directory for the project
- Initialize a Git repository and set up basic file structure
2. **Frontend**:
- Initialize a React project using Create React App
- Create components for displaying strains, products, and user profiles
- Implement routing using React Router
- Set up Redux for state management (optional)
3. **Backend**:
- Initialize a Node.js project and install necessary dependencies (Express, Mongoose, JWT, etc.)
- Set up routes for user authentication, strains, products, and reviews
- Implement controllers and models for handling database operations
4. **Database**:
- Design schemas for users, strains, products, and reviews
- Implement CRUD operations for each entity
5. **Deployment and Security**:
- Implement Infrastructure as Code (IaC) using Terraform
- Set up GitHub/GitLab for version control and CI/CD pipelines
- Use Docker for containerization and Kubernetes for orchestration
- Set up monitoring and logging with Prometheus, Grafana, and ELK Stack
- Implement security best practices including IAM roles, securing environment variables, and regular security audits
== Milestones
1. Project setup and initial commit
2. Basic frontend with routing and component structure
3. Backend API with user authentication
4. Integration of frontend with backend
5. Database design and implementation
6. Deployment to cloud environment
7. Testing and bug fixes
8. Release of MVP
== Gathering Results
- Evaluate user feedback and engagement metrics
- Monitor application performance and error logs
- Plan for future enhancements based on user needs and feedback
npm install express mongoose body-parser cors bcryptjs jsonwebtoken mongoose-encryption dotenv
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');
const dotenv = require('dotenv');
const https = require('https');
const fs = require('fs');
const userRoutes = require('./routes/user');
const strainRoutes = require('./routes/strain');
const productRoutes = require('./routes/product');
const reviewRoutes = require('./routes/review');
dotenv.config();
const app = express();
const port = process.env.PORT || 5000;
// Middleware
app.use(cors());
app.use(bodyParser.json());
// MongoDB connection
mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/marijuana-app', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch(err => console.log(err));
// Routes
app.use('/api/users', userRoutes);
app.use('/api/strains', strainRoutes);
app.use('/api/products', productRoutes);
app.use('/api/reviews', reviewRoutes);
// HTTPS setup
const options = {
key: fs.readFileSync('path/to/your/private.key'),
cert: fs.readFileSync('path/to/your/certificate.crt')
};
https.createServer(options, app).listen(port, () => {
console.log(`Secure server running on port ${port}`);
});
const mongoose = require('mongoose');
const encrypt = require('mongoose-encryption');
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
email: { type: String, required: true, unique: true },
createdAt: { type: Date, default: Date.now }
});
const encKey = process.env.ENC_KEY || 'your_secret_encryption_key';
const sigKey = process.env.SIG_KEY || 'your_signing_key';
userSchema.plugin(encrypt, { encryptionKey: encKey, signingKey: sigKey, encryptedFields: ['password'] });
const User = mongoose.model('User', userSchema);
module.exports = User;
const mongoose = require('mongoose');
const strainSchema = new mongoose.Schema({
name: { type: String, required: true },
type: { type: String, required: true },
effects: [String],
medicalUses: [String],
description: String,
createdAt: { type: Date, default: Date.now }
});
const Strain = mongoose.model('Strain', strainSchema);
module.exports = Strain;
const mongoose = require('mongoose');
const productSchema = new mongoose.Schema({
name: { type: String, required: true },
category: { type: String, required: true },
price: { type: Number, required: true },
description: String,
createdAt: { type: Date, default: Date.now }
});
const Product = mongoose.model('Product', productSchema);
module.exports = Product;
const mongoose = require('mongoose');
const reviewSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
entityId: { type: mongoose.Schema.Types.ObjectId, required: true },
entityType: { type: String, required: true },
rating: { type: Number, required: true, min: 1, max: 5 },
comment: String,
createdAt: { type: Date, default: Date.now }
});
const Review = mongoose.model('Review', reviewSchema);
module.exports = Review;
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const router = express.Router();
// Register
router.post('/register', async (req, res) => {
const { username, email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({ username, email, password: hashedPassword });
newUser.save()
.then(user => res.json(user))
.catch(err => res.status(400).json('Error: ' + err));
});
// Login
router.post('/login', async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) return res.status(400).json('User not found');
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).json('Invalid credentials');
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET || 'your_jwt_secret', { expiresIn: '1h' });
res.json({ token, user: { id: user._id, username: user.username, email: user.email } });
});
module.exports = router;
const express = require('express');
const Strain = require('../models/Strain');
const router = express.Router();
// Create a new strain
router.post('/', (req, res) => {
const newStrain = new Strain(req.body);
newStrain.save()
.then(strain => res.json(strain))
.catch(err => res.status(400).json('Error: ' + err));
});
// Get all strains
router.get('/', (req, res) => {
Strain.find()
.then(strains => res.json(strains))
.catch(err => res.status(400).json('Error: ' + err));
});
// Get a specific strain by ID
router.get('/:id', (req, res) => {
Strain.findById(req.params.id)
.then(strain => res.json(strain))
.catch(err => res.status(400).json('Error: ' + err));
});
module.exports = router;
const express = require('express');
const Product = require('../models/Product');
const router = express.Router();
// Create a new product
router.post('/', (req, res) => {
const newProduct = new Product(req.body);
new